Over a million developers have joined DZone.

Getting Started With Neuro4j Workflow

DZone's Guide to

Getting Started With Neuro4j Workflow

Neuro4j Workflow is a new workflow engine written in Java and built built to provide a variety of options for execution, processing, and modular development.

· Java Zone ·
Free Resource

Secure your Java app or API service quickly and easily with Okta's user authentication and authorization libraries. Developer accounts are free forever. Try Okta Instead.

Neuro4j Workflow is a lightweight workflow engine written entirely in Java with an Eclipse-based development environment. It's an open-source project and distributed under the Apache license

Project Features

  • Asynchronous or synchronous execution.

  • Sequential or parallel processing inside workflows.

  • It will be much easier to organize, read, and support your code.

  • No dependencies — one small JAR.

  • Reusable business code.

  • Modular development.

  • Local and remote workflow loading.

  • Easy to integrate with different technologies.

  • Dependency injection. (Google Guice, Spring, Netflix Governator).

  • Open source.

Building the Flow

So, let's build our first HelloWorld flow:

Image title

First, you need to set up Neuro4j Studio and create a new maven project:

  • Download and unzip Eclipse from the download page.

  •  Create a new maven project and import it into Eclipse.

mvn archetype:generate -DgroupId=org.neuro4j.workflow.tutorial -DartifactId=WorkflowExample -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

  • Add the Maven dependency:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

Now we are ready to create a simple flow:

  • Select package -> New -> Neuro4j Flow

Image title

  • Put "HelloFlow" into the name field -> Create

  • Add StartNode, EndNode, and CustomNode from Polette.

Image title

The next step is to add some Java code to our flow.

CustomBlock is responsible for all business logic. Classes must implement the execute(...) method from ActionBlock.

  • select package -> New -> New Custom Block:

Image title

  • put "HelloWorld" into the name field:

Image title

  • add "name" as an input parameter and message into output parameters section -> Finish

Image title

Let's update the generated code to concatenate "Hello" with an input parameter and return it as an output parameter:

package org.neuro4j.workflow.tutorial;

import static org.neuro4j.workflow.tutorial.HelloWorld.IN_NAME;
import static org.neuro4j.workflow.tutorial.HelloWorld.OUT_MESSAGE;

import org.neuro4j.workflow.ActionBlock;
import org.neuro4j.workflow.FlowContext;
import org.neuro4j.workflow.common.FlowExecutionException;
import org.neuro4j.workflow.common.ParameterDefinition;
import org.neuro4j.workflow.common.ParameterDefinitionList;
import static org.neuro4j.workflow.enums.ActionBlockCache.*;
import org.neuro4j.workflow.enums.CachedNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

 *  HelloWorld block receives name as input parameter and returns message as output parameters.
@ParameterDefinitionList(input = {
        @ParameterDefinition(name = IN_NAME, isOptional = true, type = "java.lang.String")
    output = {
        @ParameterDefinition(name = OUT_MESSAGE, isOptional = true, type = "java.lang.String")

// will create  just one instance  of HelloWorld's class in workflow
@CachedNode(type = SINGLETON)
public class HelloWorld implements ActionBlock {

    private static final Logger logger = LoggerFactory.getLogger(HelloWorld.class);

    static final String IN_NAME = "name";

    static final String OUT_MESSAGE = "message";

    public int execute(FlowContext ctx) throws FlowExecutionException {

        String name = (String) ctx.get(IN_NAME);

        String message = "Hello World! ";

        if (name != null) {
            message += name;

        logger.debug("Message: {}", message);

        ctx.put(OUT_MESSAGE, message);

        return NEXT;


Our next step is to call the Java class from the workflow.

  • Click on CustomNode -> In Property view select class -> Ok

Image title

Now we are ready to call this simple flow. Let's create a Java class — App.java with a main method.

package org.neuro4j.workflow.tutorial;

import java.util.HashMap;
import java.util.Map;

import org.neuro4j.workflow.ExecutionResult;
import org.neuro4j.workflow.common.WorkflowEngine;
import org.neuro4j.workflow.common.WorkflowEngine.ConfigBuilder;

 * This is client's class.
public class App {

    public static void main(String[] args) {

        // create engine with default configuration
        WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder());

        // put input parameters
        Map < String, Object > parameters = new HashMap < String, Object > ();
        parameters.put("name", "Workflow");

        //execute flow
        ExecutionResult result = engine.execute("org.neuro4j.workflow.tutorial.HelloFlow-Start", parameters);

        if (result.getException() == null) {
            String message = (String) result.getFlowContext().get("message");
            System.out.println("Message: " + message);
        } else {


Run client: 

mvn install exec:java -Dexec.mainClass="org.neuro4j.workflow.tutorial.App"


Message: Hello World! Workflow

What Else?

You can use your own icons for CustomBlocks

Just add the icon "HelloWorld.png" (64x52) into the org.neuro4j.workflow.tutorial folder, and Eclipse will display it in your workflow

Image title

Also, Neuro4j Studio provides a debug plugin:

Image title

Visit GitHub to find more information about the project and try other examples:

Secure your Java app or API service quickly and easily with Okta's user authentication and authorization libraries. Developer accounts are free forever. Try Okta Instead.

java ,workflow engine ,neuro4j ,tutorial ,asynchronous events

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}