Technologies used in this article :

  1. Neuro4j Workflows 3.3.1
  2. Maven 4.0
  3. Neuro4j Studio 3.0 (based on Eclipse Neon)
  4. JDK 1.8
  5. Source on GitHub

 

SpringBoot configuration

SpringBoot configuration file AppConfig.java defines WorkflowEngine and SpringContextInitStrategy which allows to initialize component inside workflow Spring's BeanFactory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Configuration
public class AppConfig {

    @Autowired
    SpringContextInitStrategy initStrategy;

    @Bean
    @Scope("singleton")
    public WorkflowEngine getWorkflowEngine() {
        return new WorkflowEngine(new ConfigBuilder().withCustomBlockInitStrategy(initStrategy));
    }

}

WelcomeController

Controller will process "/download" requests and run "org.neuro4j.workflow.DownloadPages-Start" workflow

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Controller
public class WelcomeController {

    @Autowired
    private WorkflowEngine engine;

    @RequestMapping("/")
    public String welcome(Map<String, Object> model) {
        return "welcome";
    }

    @RequestMapping("/download")
    public String download(Map<String, Object> model) {

        WorkflowRequest request = new WorkflowRequest(model);

        request.addParameter("url1", "https://en.m.wikipedia.org/wiki/Antarctica/Rothera#/random");
        request.addParameter("url2", "https://en.m.wikipedia.org/wiki/Bengal_tiger");
        request.addParameter("url3", "https://en.m.wikipedia.org/wiki/Bengal");

        ExecutionResult result = engine.execute("org.neuro4j.workflow.DownloadPages-Start", request);
        model.putAll(result.getFlowContext().getParameters());
        return "download";
    }

}

Workflow

Workflow after Fork node will run sub-flows in 3 different threads and will wait at Join node. After Join node it will continue execution in 1 "main" thread.

 

CustomBlock DownloadPage

This block defines business functionality and will call DownloadService to get content from remote server. DownloadPage has @Component annotation which allows to use Spring's BeanFactory to initialize all services defined in block (like DownloadService).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@ParameterDefinitionList(input = {
        @ParameterDefinition(name = IN_URL, isOptional = true, type = "java.lang.String") }, output = {
                @ParameterDefinition(name = OUT_DOCUMENT, isOptional = true, type = "java.lang.String") })
@CachedNode(type = SINGLETON)
@Component
public class DownloadPage implements ActionBlock {

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

    static final String IN_URL = "url";

    static final String OUT_DOCUMENT = "document";


    @Autowired
    private DownloadService service;

    public int execute(FlowContext ctx) throws FlowExecutionException {

        String url = (String) ctx.get(IN_URL);

        Logger.debug("Downloading page {}", url);

        String content = "";

        try {

            content = service.download(url);

        } catch (IOException e) {
            Logger.error("Error during downloading url {}", url, e);
        }

        ctx.put(OUT_DOCUMENT, content);

        return NEXT;
    }

}

JsoupDownloadService

Will be initialized by Spring and assigned to DownloadPage block

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Service
public class JsoupDownloadService implements DownloadService{

    @Override
    public String download(String url) throws IOException {
        Document doc = Jsoup.connect(url).validateTLSCertificates(false).get();
        if (doc != null) {
            String content = doc.html();
            return content;
        }
        return "";
    }

}

Running application

Run application with command

mvn clean install spring-boot:run

Open http://localhost:8080/download

What's next?