Skip to content
Esa Puttonen edited this page Oct 4, 2024 · 19 revisions

Spring Boot is a popular way for creating stand-alone Spring applications. This page contains instructions for setting up nFlow on top of vanilla Spring Boot project using Maven or Gradle.

Bare minimum example

The bare minimum includes the nFlow engine only configuration for Spring Boot. The database is in-memory H2. The full working example can be found from nFlow Github repository.

  1. Generate Spring Boot application using Initializr. Choose your preferred project type (Maven/Gradle) and add JDBC API and H2 Database dependencies.

  2. Enable nflow.db.h2 profile and disable verbose logging by adding the following lines to src/main/resources/application.properties:

spring.profiles.active=nflow.db.h2
logging.level.root=WARN
  1. Add nflow-engine library dependency
  • Maven: pom.xml
<dependency>
  <groupId>io.nflow</groupId>
  <artifactId>nflow-engine</artifactId>
  <version>10.0.0</version>
</dependency>
  • Gradle: build.gradle
compile("io.nflow:nflow-engine:10.0.0")
  1. Import nFlow engine configuration in Spring Boot application class:
...
import org.springframework.context.annotation.Import; // add this
import io.nflow.engine.config.EngineConfiguration;    // add this

@SpringBootApplication
@Import(EngineConfiguration.class)                    // add this
public class DemoApplication {
...
  1. Create an example workflow that increments and outputs a counter every 10 seconds.

  2. Build the Spring Boot application in command line:

  • Maven
mvn install
  • Gradle
./gradlew build
  1. Start the Spring Boot application and observe the counter value is printed every 10 seconds on each ExampleWorkflow step:
  • Maven
java -jar target/demo-0.0.1-SNAPSHOT.jar
  • Gradle
java -jar build/libs/demo-0.0.1-SNAPSHOT.jar

Full stack example

The full stack includes the nFlow engine, REST API and Explorer user interface for Spring Boot. The database is in-memory H2. The full working example can be found from nFlow Github repository.

  1. Generate Spring Boot application using Initializr. Choose your preferred project type (Maven/Gradle) and add Spring Web, JDBC API and H2 Database dependencies.

  2. Enable nflow.db.h2 profile and disable verbose logging by adding the following lines to src/main/resources/application.properties:

spring.profiles.active=nflow.db.h2
logging.level.root=WARN
  1. Add nflow-rest-api-spring-web library dependency. Note: nflow-rest-api-jax-rs is also available, if you're not using Spring Web.
  • Maven: pom.xml
<dependency>
  <groupId>io.nflow</groupId>
  <artifactId>nflow-rest-api-spring-web</artifactId>
  <version>10.0.0</version>
</dependency>
  • Gradle: build.gradle
compile("io.nflow:nflow-rest-api-spring-web:10.0.0")
  1. Import nFlow engine configuration in Spring Boot application class
import org.springframework.context.annotation.Import; // add this
import io.nflow.rest.config.RestConfiguration;        // add this

@SpringBootApplication
@Import(RestConfiguration.class)                      // add this
public class DemoApplication {
  1. Create an example workflow that increments and outputs a counter every 10 seconds.

  2. Download and package nFlow Explorer static resources inside Spring Boot uberjar.

  • Gradle: build.gradle
plugins {
  id 'de.undercouch.download' version '5.4.0'
}

configurations {
  nflowExplorer
}

// add to dependencies
nflowExplorer group: 'io.nflow', name: 'nflow-explorer', version: '10.0.0', ext: 'tar.gz'

task resolveNflowExplorer(type: Copy) {
  destinationDir = file("$buildDir/resources/main/static/explorer")
  from { tarTree(resources.gzip(configurations.nflowExplorer.singleFile)) }
}

processResources.dependsOn resolveNflowExplorer
  • Maven: pom.xml
<build>
  <plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-dependency-plugin</artifactId>
      <executions>
        <execution>
          <id>unpack</id>
          <phase>generate-resources</phase>
          <goals>
            <goal>unpack</goal>
          </goals>
          <configuration>
            <artifactItems>
              <artifactItem>
                <groupId>io.nflow</groupId>
                <artifactId>nflow-explorer</artifactId>
                <version>10.0.0</version>
                <type>tar.gz</type>
                <overWrite>true</overWrite>
                <outputDirectory>${project.build.outputDirectory}/static/explorer</outputDirectory>
              </artifactItem>
            </artifactItems>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
  1. In addition to static resources, nFlow Explorer needs to know the address and configuration of the nFlow REST API. Add nFlow Explorer configuration by creating a file src/main/resources/static/explorer/config.js. For more configuration options see default config.js.
var Config = new function() {
  this.refreshSeconds = 60;

  this.nflowEndpoints = [
    {
      id: 'localhost',
      title: 'local nflow instance',
      apiUrl: '/nflow/api',
      docUrl: '/nflow/ui/doc/'
    },
  ];
};

  1. Build the Spring Boot application in command line
  • Maven
mvn install
  • Gradle
./gradlew build
  1. Start the Spring Boot application and observe the counter value is printed every 10 seconds on each ExampleWorkflow step. You can also open up local nFlow Explorer user interface.
  • Maven
java -jar target/demo-0.0.1-SNAPSHOT.jar
  • Gradle
java -jar build/libs/demo-0.0.1-SNAPSHOT.jar

Create an example workflow

  1. Copy & paste the following workflow definition to a new class file ExampleWorkflow:
import org.joda.time.DateTime;

import io.nflow.engine.workflow.definition.NextAction;
import io.nflow.engine.workflow.definition.StateExecution;
import io.nflow.engine.workflow.definition.WorkflowDefinition;
import io.nflow.engine.workflow.definition.WorkflowStateType;

import static io.nflow.engine.workflow.definition.WorkflowStateType.manual;
import static io.nflow.engine.workflow.definition.WorkflowStateType.start;

public class ExampleWorkflow extends WorkflowDefinition<ExampleWorkflow.State> {

  public static final String TYPE = "repeatingWorkflow";
  public static final String VAR_COUNTER = "VAR_COUNTER";

  public enum State implements io.nflow.engine.workflow.definition.WorkflowState {
    repeat(start, "Repeating state"),
    error(manual, "Error state");

    private WorkflowStateType type;
    private String description;

    State(WorkflowStateType type, String description) {
      this.type = type;
      this.description = description;
    }

    @Override
    public WorkflowStateType getType() {
      return type;
    }

    @Override
    public String getDescription() {
      return description;
    }
  }

  public ExampleWorkflow() {
    super(TYPE, State.repeat, State.error);
    permit(State.repeat, State.repeat);
  }

  public NextAction repeat(StateExecution execution) {
    System.out.println("Counter: " + execution.getVariable(VAR_COUNTER));
    execution.setVariable(VAR_COUNTER, execution.getVariable(VAR_COUNTER, Integer.class) + 1);
    return NextAction.moveToStateAfter(State.repeat, DateTime.now().plusSeconds(10), "Next iteration");
  }
}
  1. Add an ExampleWorkflow bean to your Spring Boot application:
@Bean
public ExampleWorkflow exampleWorkflow() {
  return new ExampleWorkflow();
}
  1. Create new ExampleWorkflow instance on application startup by using WorkflowInstanceFactory and WorkflowInstanceService in the Spring Boot application:
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;

import io.nflow.engine.service.WorkflowInstanceService;
import io.nflow.engine.workflow.instance.WorkflowInstanceFactory;
...
  @Inject
  private WorkflowInstanceService workflowInstances;

  @Inject
  private WorkflowInstanceFactory workflowInstanceFactory;

  @EventListener(ApplicationReadyEvent.class)
  public void insertWorkflowInstance() {
    workflowInstances.insertWorkflowInstance(workflowInstanceFactory.newWorkflowInstanceBuilder()
        .setType(ExampleWorkflow.TYPE)
        .setExternalId("example")
        .putStateVariable(ExampleWorkflow.VAR_COUNTER, 0)
        .build());
  }