Java Module Project Structure Overview
After implementing a module, a ZIP archive containing the module JARs, dependencies, and the scaleoutPackage.json
can be deployed through the ScaleOut Active Caching UI. This ZIP archive is referred to as the ModulePackage
Module Dependencies
Module Clients (API or MSG) should reference the com.scaleoutsoftware.modules:client
library.
<dependency>
<groupId>com.scaleoutsoftware.modules</groupId>
<artifactId>client</artifactId>
<version>1.0.0</version>
</dependency>
implementation group: 'com.scaleoutsoftware.modules', name: 'client', version: '1.0.0'
implementation group: 'com.scaleoutsoftware.modules:client:1.0.0'
implementation("com.scaleoutsoftware.modules:client:1.0.0")
Module Packages (API or MSG) should reference the com.scaleoutsoftware.modules:hosting
library.
<dependency>
<groupId>com.scaleoutsoftware.modules</groupId>
<artifactId>hosting</artifactId>
<version>1.0.0</version>
</dependency>
implementation group: 'com.scaleoutsoftware.modules', name: 'hosting', version: '1.0.0'
implementation group: 'com.scaleoutsoftware.modules:hosting:1.0.0'
implementation("com.scaleoutsoftware.modules:hosting:1.0.0")
Module Package Entry Point
The ActiveCaching service uses the module package’s defined entry point to launch the module across a cluster of ScaleOut StateServer hosts. The scaleout-msg-module
and scaleout-api-module
archetypes generate an entry point that does not require any additional configuration. The generated entry point is available in the src/main/packageDirs/Main.java
.
The following is an example from the ShoppingCart
demo:
public class Main {
public static void main(String[] args) {
// instantiate the module package
ModulePackage modulePackage = new ModulePackage();
// define the ApiModuleOptions
ApiModuleOptions<ShoppingCart> apiModuleOptions = new ApiModuleOptionsBuilder<ShoppingCart>(ShoppingCart.class).build();
// add the API module to the package
modulePackage.addApiModule("ShoppingCart", new ShoppingCartApiProcessor(), apiModuleOptions);
try {
// wait for events
modulePackage.waitForEvents();
} catch (ModuleRegistrationException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Notably, the entry point is responsible for the following:
Instantiating the
ModulePackage
.Instantiating the
ModuleOptions
.Adding the user-created module to the
ModulePackage
Calling
waitForEvents()
on theModulePackage
instance.
Testing a Module Locally
Requirements: ScaleOut StateServer is installed and running locally.
Developers can test the module package by:
Creating a unit test or standalone app.
Instantiating the
ModulePackage
.Instantiating the
ModuleOptions
.Adding the user created module to the
ModulePackage
Calling
runLocalDevelopmentEnvironment()
on theModulePackage
instance.
This non-blocking method allows the module to be self-hosted and handle incoming endpoint invocations for API modules and receive MSGs for MSG modules on a local server.
In addition to running the module package locally, developers can run a module client locally as well.
The code to create a MSG module client suitable for local testing is syntactically similar to creating a traditional MSG module client. Instead of specifying a GridConnection
and build()
– call buildLocalDevelopmentClient
on the MsgModuleClientBuilder
:
MsgModuleClient<Flight> client = new MsgModuleClientBuilder<Flight>("Flight", Flight.class).buildLocalDevelopmentClient();
The code to create an API client suitable for local testing is syntactically similar to creating a traditional API client. Specify the GridConnection
’s connection string as the Constants.DEVELOPMENT_CONNECTION_STRING
:
ExampleClient exampleClient = new ExampleClient(GridConnection.connect(Constants.DEVELOPMENT_CONNECTION_STRING), "ShoppingCart");
scaleoutPackage.json
The scaleoutPackage.json
metadata file is used to describe the module. The fields are:
Property |
Description |
---|---|
|
An array of Modules (see below) |
|
The entry point into the Module |
Module JSON definition
Property |
Description |
---|---|
|
The name of the module |
|
java or dotnet |
|
api or msg |
Adding Automatic Module Packaging to Maven Projects
The following package plugins will allow your Maven project to generate a ZIP archive for deployment. This task relies on the scaleoutPackage.json configuration file to be created/configured and then placed in the src/main/resources
directory.
Begin by creating deployment.xml
in the src\assembly
directory (create the assembly directory if it does not already exist) with the following contents:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 https://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>deployment</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<!-- Compiled JAR -->
<fileSet>
<directory>${project.build.directory}</directory>
<includes>
<include>${project.build.finalName}.jar</include>
</includes>
</fileSet>
<!-- Dependencies -->
<fileSet>
<directory>${project.build.directory}/dependency-jars</directory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<!-- scaleoutPackage.json -->
<fileSet>
<directory>src/main/resources</directory>
<includes>
<include>scaleoutPackage.json</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Next, add the following plugins to the project’s pom.xml
under the <build><plugins>
tag:
<!-- other plugins above... -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>make-zip</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/assembly/deployment.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dependency-jars</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<!-- other plugins below... -->
Now run the following:
mvn package
Adding Automatic Module Packaging to Gradle Projects
The following packageForDeployment
ZIP task will generate a package for Gradle projects. This task relies on the scaleoutPackage.json configuration file to be created/configured and then placed in the src/main/resources
directory. Add the following to your Gradle build:
tasks.register('packageForDeployment', Zip) {
group = 'distribution'
description = 'Packages build output, dependencies, and scaleoutPackage.json into a deployable ZIP'
// The output zip will be named like: project-name.zip
archiveFileName = "${project.name}.zip"
destinationDirectory = layout.buildDirectory.dir("deployment")
// Include the compiled JAR
from(jar) {
into('')
}
// Include all runtime dependencies (flattened)
from(configurations.runtimeClasspath) {
into('')
// Optional: filter to include only JARs
include '*.jar'
}
// Include scaleoutPackage.json from resources
from('src/main/resources') {
include 'scaleoutPackage.json'
into('')
}
// Fail the build if scaleoutPackage.json is missing
doFirst {
def scaleoutPackageFile = file('src/main/resources/scaleoutPackage.json')
if (!scaleoutPackageFile.exists()) {
throw new GradleException("Missing required file: src/main/resources/scaleoutPackage.json")
}
}
}
tasks.register<Zip>("packageForDeployment") {
group = "distribution"
description = "Packages build output, dependencies, and scaleoutPackage.json into a deployable ZIP"
archiveFileName.set("${project.name}.zip")
destinationDirectory.set(layout.buildDirectory.dir("deployment"))
// Include compiled JAR
from(tasks.named("jar")) {
into("")
}
// Include runtime dependencies
from(configurations.runtimeClasspath) {
into("")
include("*.jar")
}
// Include scaleoutPackage from resources
from("src/main/resources") {
include("scaleoutPackage")
into("")
}
// Fail if scaleoutPackage is missing
doFirst {
val scaleoutPackageFile = file("src/main/resources/scaleoutPackage.json")
if (!scaleoutPackageFile.exists()) {
throw GradleException("Missing required file: src/main/resources/scaleoutPackage.json")
}
}
}
Then run the following to generate the YourProjectName.zip
ZIP package in the project’s build/deployment/
directory.
./gradlew clean build packageForDeployment
.\gradlew.bat clean build packageForDeployment
ModulePackage ZIP Archive
After implementing a module, a ZIP archive containing the module JARs, dependencies, and the scaleoutPackage.json
can be deployed through the ScaleOut Active Caching UI.
You can generate the deployable ZIP archive through your build tool by packaging the scaleoutPackage.json
, the project artifact, and the project’s dependencies. Alternatively, if using a different java build tool you can manually create the module package ZIP archive. To do this, collect the java project’s build output as a JAR, the dependency JARs, the scaleoutPackage.json configuration file, and compress them into a ZIP archive.
The sequence for creating the module package ZIP archive is as follows:
Compile module classes
JAR module classes
Copy build output into a common directory, i.e. _MyModule_
Copy all dependencies of module classes into the MyModule directory
Copy scaleoutPackage.json into MyModule directory
The MyModule directory structure should now appear as follows:
MyModule
|
\
scaleoutPackage.json
MyModule-1.0.jar
hosting-1.0.0.jar
... more dependencies ...
ZIP the _contents_ of the MyModule directory. Now the module package can be uploaded to the ScaleOut Active Caching web UI.
API Javadoc
API javadoc is available on the ScaleOut Software website.