Skip to main content
Version: 10.3.1

JNW Toolkit overview

JNW Toolkit is a collection of libraries that simplify development with the Java Native Worker (JNW). Each library can be used independently and implements some specific feature that can be used when needed and ignored when it is not.

Requirements

The following components are required for the Worker Development Toolkit:

  • JDK 21.x. Verify availability by running java -version in the command line.
  • Maven 3.9.x. Verify availability by running mvn -version in the command line.

Bill of Materials

Each version of JNW Toolkit is built for compatibility with a specific version of the JNW. The jnw-tookit-bom module is a Bill of Materials or BOM. When imported, it provides versions for all JNW modules, transitive dependencies required by it, and other compatible utilities like the worker-task-test library.

tip

For the JNW compatibility matrix, see the Java Native Workers guide.

To use jnw-tookit-bom, complete the following steps:

  1. Add a version of jnw-toolkit to the <properties> section of your Maven project:

    <properties>
    <wf.jnw-toolkit.version>1.0.0.17</wf.jnw-toolkit.version>
    <!--
    1.0.0.17 is the earliest version that supports all features described in the article.
    1.0.0.17.1 is the earliest version that supports all features described in the article for Platform version 10.2.8.
    You might need to look for the recent version.
    -->
    </properties>
  2. If your project is a part of the workfusion-meta pipeline, add a dependency to jnw-toolkit to the components.yaml file of the workfusion-meta project:

    your-project:
    dependencies:
    - jnw-toolkit
  3. Import jnw-toolkit-parent in the <dependencyManagement> section of the Maven project.

    <dependencyManagement>
    <dependencies>
    <dependency>
    <groupId>com.workfusion.jnw.toolkit</groupId>
    <artifactId>jnw-toolkit-bom</artifactId>
    <version>${wf.jnw-toolkit.version}</version>
    <type>pom</type>
    <scope>import</scope>
    </dependency>
    </dependencies>
    </dependencyManagement>

You can add any module of JNW Toolkit, the JNW, the worker-task-test library, or any other dependency mentioned in jnw-tookit-bom as a project dependency without worrying about which version to use, for example:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-auto-task-processor</artifactId>
</dependency>
</dependencies>
note

Other chapters of the article are written with the assumption that jnw-tookit-bom is imported into the project, so dependency versions are not mentioned.

Code generation

The jnw-toolkit-auto-task-processor and jnw-toolkit-auto-task-processor-xml modules are responsible for the auto-generation of Task Processor classes and other boilerplate code required for running Bot Tasks on the JNW.

Configuration

Add the jnw-toolkit-configuration module as a project dependency:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-configuration</artifactId>
</dependency>
</dependencies>

Now, you can inject an object of the TaskConfigurationProvider class:

@Autowired
TaskConfigurationProvider taskConfigurationProvider;

You can call the TaskConfigurationProvider methods to get an instance of the JsonConfiguration class:

  • TaskConfigurationProvider.getDigitalWorkerConfiguration() returns an object containing configuration data for the AI Agent.

  • TaskConfigurationProvider.getTaskConfiguration(TaskConfiguration) returns an object containing configuration data for a currently running task.

  • TaskConfigurationProvider.getMergedConfiguration(TaskConfiguration) returns an object that tries to read the configuration first from the context of the task and then from the context of the AI Agent.

info

The JsonConfiguration instances must not be stored between executions of the task. Every time your code needs to access the configuration, TaskConfigurationProvider.get... must be called to retrieve a fresh up-to-date instance.

JsonConfiguration offers the following methods:

Optional<String> getProperty(String name);
String getRequiredProperty(String name);
<T> Optional<T> getProperty(String name, Class<T> valueClass);
<T> T getRequiredProperty(String name, Class<T> valueClass);
<T> List<T> getArrayProperty(String name, Class<T> valueClass);

They are well documented in the source code and designed like counterparts in ODF 2. You can use the JsonPath expressions to retrieve data from complex and nested JSON data structures.

Overriding configuration

You can provide additional configuration data to JNW Toolkit through Spring configuration properties. First, all configurations returned by TaskConfigurationProvider read properties from the additional data and only then from the task or AI Agent configuration.

There are several options you can use:

  • Add JSON to the jnw.configuration.json.string property.
  • Add the name of the file with the JSON content to the jnw.configuration.json.file property.

If used simultaneously, jnw.configuration.json.string takes precedence over jnw.configuration.json.file.

See example

A JsonConfiguration object returned by TaskConfigurationProvider.getMergedConfiguration() searches for properties in the following order:

  1. In the content passed in the jnw.configuration.json.string property (if present).

  2. In the content of the file passed in the jnw.configuration.json.file property (if present).

  3. In the configuration data for a currently running Bot Task.

  4. In the configuration data for the AI Agent that contains the Business Process with the currently running Bot Task.

Execution context

Add the jnw-toolkit-context module as a project dependency:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-context</artifactId>
</dependency>
</dependencies>

Now, you can inject an object of the TaskExecutionContext class:

@Autowired
TaskExecutionContext taskExecutionContext;

You can use the class methods to get the assorted context and configuration information for a currently running task:

  • TaskExecutionContext.getBpExecutionUuid() gets a UUID of a current Business Process execution.

  • TaskExecutionContext.getDigitalWorkerConfigurationJson() gets a raw configuration JSON for the AI Agent used by TaskConfigurationProvider.getDigitalWorkerConfiguration().

  • TaskExecutionContext.getDigitalWorkerInfo() gets an object with information about the use case code and version and other information that Control Tower reads from the meta-info.json file of an Asset Bundle.

Control Tower services

Add the jnw-toolkit-control-tower-services module as a project dependency:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-control-tower-services</artifactId>
</dependency>
</dependencies>

Now, you can inject objects of the ControlTowerBpService and ControlTowerTaskService classes:

@Autowired
ControlTowerBpService controlTowerBpService;

@Autowired
ControlTowerTaskService ControlTowerTaskService;

ControlTowerBpService sends a request to Control Tower for information on any Business Process by its ID.

ControlTowerTaskService starts a task or Business Process in Control Tower by providing a Campaign ID and input data.

For more details on API, refer to its documentation in the source code.

Access to Control Tower Data Stores

Add the jnw-toolkit-datastores module as a project dependency:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-datastores</artifactId>
</dependency>
</dependencies>

This module provides a Spring DataSource configured to access the Control Tower database. With it, all Spring-compatible database frameworks are by default set up to access the Control Tower database (DB). You can use Spring Data JDBC, JPA, Hibernate, or any other compatible library to access the DB in any way you prefer. However, this approach requires you to handle all conventions imposed by Control Tower yourself.

If you want to write your database layer using the ORMLite and Repository classes, as was done in ODF 2, see Access Data Stores using ORMLite and Spring JDBC.

If you port a project from ODF 2 and would like to continue using ORMLite and ODF 2 Repository classes, use the compatibility tool in ODF 2. For more details, see Use ODF 2 Data Stores in Java Native Worker.

caution

Using both approaches simultaneously is error-prone and not recommended.

Access Data Stores using ORMLite and Spring JDBC

Control Tower imposes certain conventions for the names of database tables used by AI Agents. The goal is to avoid naming conflicts between different AI Agents, separate data by AI Agent version, and enable the creation of reusable bot steps that use the tables of the AI Agent they belong to. JNW Toolkit offers a set of tools to automate this process.

With this approach, the name of the database table is automatically adjusted at runtime based on the AI Agent's name and version.

If you want to use Spring JDBC, add the jnw-toolkit-spring-jdbc module as a project dependency:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-spring-jdbc</artifactId>
</dependency>
</dependencies>

This module replaces the standard Spring implementation of the org.springframework.data.relational.core.mapping.NamingStrategy interface with a custom implementation responsible for adjusting table names at runtime.

If you want to use the ORMLite library to access the database in the ORM style, add the jnw-toolkit-ormlite module as a project dependency instead:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-ormlite</artifactId>
</dependency>
</dependencies>

For details, see Work with Data Stores in JNW Toolkit.

S3 Client

Add the jnw-toolkit-s3-client module as a project dependency:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-s3-client</artifactId>
</dependency>
</dependencies>

Now, you can inject an object of the S3Service class:

@Autowired
com.workfusion.jnw.toolkit.s3.S3Service s3Service;

S3Service is a convenience API wrapper for the S3 client library by Amazon. It is configured by default to access the S3 file storage.

For more details on API, refer to the documentation in the source code. It is designed in the same way as its counterpart in ODF 2.

You can also inject AmazonS3 or AmazonS3ClientBuilder if you need some low-level API that is not provided by S3Service. The objects are also configured by default to access S3.

Bot Task lifecycle

Add the jnw-toolkit-lifecycle module as a project dependency:

<dependencies>
<dependency>
<groupId>com.workfusion.jnw.toolkit</groupId>
<artifactId>jnw-toolkit-lifecycle</artifactId>
</dependency>
</dependencies>

Now, you can create your Bot Task like in ODF 2, with init(), shouldRun(), and other lifecycle methods. To do this, implement the ClassicLifecycle interface and inject the ClassicLifecycleRunner object:

@TaskProcessor(id = "lifecycle-demo-task")
public class LifecycleDemoTaskProcessor implements ITaskProcessor, ClassicLifecycle {

@Autowired
ClassicLifecycleRunner lifecycle;

@Override
public TaskOutputData process(TaskInputData taskInputData) throws TaskProcessorException {
// will call lifecycle methods according to logic similar to one in ODF 2
return lifecycle.run(this, taskInputData);
}

@Override
public void init(TaskInputData input) {
// do something here
}

@Override
public boolean shouldRun(TaskInputData input) {
// do something here
}

@Override
public TaskOutputData run(TaskInputData input) {
// do something here
}

@Override
public TaskOutputData handleException(TaskInputData input, Exception e) {
// do something here
}
}

For more details on API, refer to the ClassicLifecycle and ClassicLifecycleRunner source code.