org.sterl.pmw:pmw-core

Poor mans workflow engine core which has no framework dependencies


Keywords
quartz, quartz-scheduler, spring, spring-boot, workflow, workflow-dashboard, workflow-engine
License
MIT

Documentation

Java CI with Maven

Poor Mans Workflow for Spring

Design-Goals

Build a very basic workflow engine which does only really basic stuff and is understood in a second.

  • one simple jar to get it running
  • no own deployment of a workflow server or any stuff
  • Java DSL, keep the code in java
  • Visual representation of the workflow

ToDo

  • First Spring integration
  • First PlantUML integration
  • Wait as own step
  • Await and resume
  • Transactional and non transactional steps
  • Trigger workflows in an own step
  • Link to workflows in repository using trigger->
  • Error steps

Maven

Select latest version: https://central.sonatype.com/search?q=g%3Aorg.sterl.pmw

<dependency>
    <groupId>org.sterl.pmw</groupId>
    <artifactId>spring-pmw-core</artifactId>
    <version>2.x.x</version>
</dependency>

Define a workflow

check-warehouse

@Configuration
public class NewItemArrivedWorkflow {

    @Bean
    Workflow<NewItemArrivedState> restorePriceWorkflow(DiscountComponent discountComponent) {
        return Workflow.builder("Restore Item Price", () -> NewItemArrivedState.builder().build())
                .next("updatePrice", c -> discountComponent.setPrize(c.data().getItemId(), c.data().getOriginalPrice()))
                .next("sendMail", s -> {})
                .build();
    }

    @Bean
    Workflow<NewItemArrivedState> checkWarehouseWorkflow(
            WarehouseService warehouseService,
            UpdateInStockCountComponent updateStock,
            WarehouseStockComponent createStock,
            DiscountComponent discountComponent,
            Workflow<NewItemArrivedState> restorePriceWorkflow) {

        return Workflow.builder("Check Warehouse", () -> NewItemArrivedState.builder().build())
                .next().description("check warehouse for new stock")
                    .function(c -> createStock.checkWarehouseForNewStock(c.data().getItemId()))
                    .build()
                .next("update item stock", c -> {
                    final var s = c.data();
                    final long stockCount = warehouseService.countStock(s.getItemId());
                    updateStock.updateInStockCount(s.getItemId(), stockCount);
                    s.setWarehouseStockCount(stockCount);
                })
                .sleep("wait", "Wait if stock is > 40", (s) -> s.getWarehouseStockCount() > 40 ? Duration.ofMinutes(2) : Duration.ZERO)
                .choose("check stock", s -> {
                        if (s.getWarehouseStockCount() > 40) return "discount-price";
                        else return "buy-new-items";
                    })
                    .ifTrigger("discount-price", restorePriceWorkflow)
                        .description("WarehouseStockCount > 40")
                        .delay(Duration.ofMinutes(2))
                        .function(s -> {
                            var originalPrice = discountComponent.applyDiscount(s.getItemId(), 
                                    s.getWarehouseStockCount());
                            s.setOriginalPrice(originalPrice);
                            return s;
                        }).build()
                    .ifSelected("buy-new-items", c -> {})
                    .build()
                .build();
    }
}

Export Workflow as UML

Example Code

class CheckWarehouseWorkflowPrintTest {

    private NewItemArrivedWorkflow subject = new NewItemArrivedWorkflow();

    WorkflowRepository repo = new WorkflowRepository();
    WorkflowUmlService umlService = new WorkflowUmlService(repo);
    
    Workflow<NewItemArrivedState> restorePriceWorkflow;
    Workflow<NewItemArrivedState> checkWarehouseWorkflow;

    @BeforeEach
    void setUp() throws Exception {
        repo.clear();
        restorePriceWorkflow = subject.restorePriceWorkflow(mock(DiscountComponent.class));
        checkWarehouseWorkflow = subject.checkWarehouseWorkflow(
                mock(WarehouseService.class), 
                mock(UpdateInStockCountComponent.class),
                mock(WarehouseStockComponent.class),
                mock(DiscountComponent.class),
                restorePriceWorkflow);
        
        repo.register("restorePriceWorkflow", restorePriceWorkflow);
        repo.register("checkWarehouseWorkflow", checkWarehouseWorkflow);
    }

    @Test
    void testWriteSvg() throws Exception {

        PlantUmlWritter.writeAsPlantUmlSvg("./check-warehouse.svg", checkWarehouseWorkflow, umlService);
    }
    
    @Test
    void testWriteUml() throws Exception {
        System.err.println(
                umlService.printWorkflow(checkWarehouseWorkflow)
        );
    }
}

Use the UI

Maven

<dependency>
    <groupId>org.sterl.pmw</groupId>
    <artifactId>spring-pmw-core</artifactId>
    <version>2.x.x</version>
</dependency>

Spring

@EnableWorkflows
@EnableWorkflowsUI
@SpringBootApplication
public class StoreApplication {

Preview

PMW Admin Dashboard

Links

IDE

Looking for a real workflow engine