-
Download the latest release from forklift-server-x.x.zip.
-
unzip the download
-
Using a command line,
cd
into the unzipped directory -
Create a directory named
forklift
in your home directory.
$ mkdir ~/forklift
-
Create a sub-directory named deploy.
$ mkdir ~/forklift/deploy
Within the forklift-server-x.x directory run the following command:
$ bin/forklift-server -monitor1 ~/forklift/deploy -url embedded
At this point, you should see a lot of log output from Forklift showing that it is running, but it really isn’t doing anything other than waiting for you to start deploying consumers to it.
This guide will lead you through writing a quick consumer. Provided are build scripts for both Maven and Sbt. Please choose the method that you are most comfortable using. You can also do this directly within and IDE such as Eclipse, but this will be left up to the developer as their own exercise.
The Gradle build file for your first consumer, if you’ve moved on from Maven or sbt.
plugins {
// Apply the java-library plugin to add support for Java Library
id 'com.github.johnrengelman.shadow' version '6.0.0'
id 'java-library'
}
repositories {
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
dependencies {
// This dependency is exported to consumers, that is to say found on their compile classpath.
api 'com.github.dcshock:forklift:3.7'
// Use JUnit Jupiter API for testing.
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2'
// Use JUnit Jupiter Engine for testing.
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.2'
}
test {
// Use junit platform for unit tests
useJUnitPlatform()
}
The Maven build file for your first consumer, if you’re into that kind of thing.
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>forklift.consumer</groupId>
<artifactId>MyExampleConsumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>My Example Consumer</name>
<description>An example Forklift consumer.</description>
<repositories>
<repository>
<id>oss-sonatype</id>
<name>oss-sonatype</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.dcshock</groupId>
<artifactId>forklift</artifactId>
<version>[3.7,)</version>
</dependency>
</dependencies>
</project>
The Sbt build file for your first consumer, if you’re into that kind of thing.
import com.github.dcshock.SbtBinks._
organization := "forklift.consumer"
name := "MyExampleConsumer"
version := "0.1"
libraryDependencies ++= Seq(
"com.github.dcshock" % "forklift" % "[3.7,)" % "provided"
)
resolvers ++= Seq(
"Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
)
// Inform sbt-eclipse to not add Scala nature
EclipseKeys.projectFlavor := EclipseProjectFlavor.Java
// Remove scala dependency for pure Java libraries
autoScalaLibrary := false
// Remove the scala version from the generated/published artifact
crossPaths := false
// With this enabled, compiled jars are easier to debug in other projects
// variable names are visible.
javacOptions in compile ++= Seq("-source", "1.8", "-g:lines,vars,source", "-deprecation")
javacOptions in doc += "-Xdoclint:none"
addCommandAlias("dist", ";compile;binks")
binksSettings
For sbt, you will also be required to add these lines to your project/plugins.sbt
addSbtPlugin("com.github.dcshock" % "sbt-binks" % "0.1")
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "3.0.0")
The first example, is very simple and should be easily understood by most developers. It listens to the "test" queue and then logs out the message it receives.
The source code is as follows:
package forklift.consumer;
import forklift.decorators.Message;
import forklift.decorators.OnMessage;
import forklift.decorators.Queue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
@Queue("test") // (1)
public class MyExampleConsumer {
Logger log = LoggerFactory.getLogger(MyExampleConsumer.class);
@Message // (2)
public Map<String, String> msg;
@OnMessage // (3)
public void processMyMessage() {
log.info("My message was: {}", msg);
}
}
-
Tells the consumer to listen to /queue/test for messages
-
Injects the message into the msg property.
-
Tells Forklift to run this method when a message is received.
$ ./gradlew package
$ mvn package
Now your jar will be available in the target directory named MyExampleConsumer-0.0.1-SNAPSHOT.jar
$ sbt package
Now your jar will be available in the target directory named myexampleconsumer-0.1.jar
With your jar now existing, it is quite easy to deploy your jar into the running Forklift instance. Just copy your jar file into ~/forklift/deploy and you should see log messages showing that the consumer is ready to consume messages on /queue/test. It may take a second or two since the deployment scanner is on a timer thread. See the following output from the logger:
{"timestamp":"2015-06-15T17:18:32.439Z","level":"INFO","thread":"run-main-0","logger":"org.reflections.Reflections","message":"Reflections took 54 ms to scan 1 urls, producing 1 keys and 1 values ","context":"default"}
{"timestamp":"2015-06-15T17:18:32.444Z","level":"INFO","thread":"run-main-0","logger":"forklift.consumer.ConsumerDeploymentEvents","message":"Deploying: Deployment [queues=[class forklift.consumer.MyExampleConsumer], topics=[], cl=forklift.classloader.ChildFirstClassLoader@5cbdc534, deployedFile=/Users/dthompson/forklift/deploy/myexampleconsumer-0.1.jar, reflections=org.reflections.Reflections@4e6016c]","context":"default"}
{"timestamp":"2015-06-15T17:18:32.458Z","level":"INFO","thread":"consumer-deployment-events-1","logger":"consumer-thread-test:1","message":"starting consumer","context":"default"}
In this Quickstart guide, Forklift is using an embedded version of ActiveMQ, so there isn’t a built-in way to send messages to a queue or topic. Most languages have API libraries that allow the developer to send messages to a broker. Below is a list of several of the APIs available.
-
stomp.py - A Python library for sending messages to ActiveMQ that has the stomp protocol enabled. Works okay for Json objects, but for K/V pairs needs modifications since its not possible to send newline characters.
-
stomp-client - For node.js, this client library can help easily send messages to to ActiveMQ. Our example will show how to use this library.
-
Net::STOMP::Client - Perl library for working with communicating with the Stomp protocol. Contributed by a developer at CERN, this API is quite robust.
-
Forklift Producer - A little more heavy-weight API for Java, but uses the same ActiveMQ connector that Forklift uses. It is based on JMS not the Stomp protocol. More information can be found outside the Quickstart guide.
-
Install node.js. For a quick reference, please see this howto.
-
Install npm (node package manager). Using the same method for installing node.js, you should be able to install npm as well.
-
Create a directory where you can write a small node application and cd into that directory.
-
Install the node stomp-client module.
npm install stomp-client
-
Modify frames.js. There is a small issue that needs to be corrected in the stomp-client that needs fixed in order to let our node application work.
Within the following file, modify the code
if (this.body.length > 0) {
to
if (this.body.length > 0 && !this.headers.hasOwnProperty("suppress-content-length")) {
Once you’ve completed the modification, create the node program below:
var Stomp = require('stomp-client');
var dest = process.argv[2];
var client = new Stomp('localhost', 61613, null, null);
client.on('error', function(e) {
console.log(e);
});
client.connect(function(sessionId) {
var msg = process.argv[3];
client.publish(dest, msg, {"suppress-content-length":"true", "persistent":"true"});
client.disconnect();
});
From command line, run the node program which you just created.
$ node sendmessage.js /queue/test $'who=Batman\ntype=Bat signal\n'
Notice the $'
syntax. That syntax allows you to send newlines within your message.
At this point, you should be able to look at the log output of Forklift and you
should see your message logged out. For example:
{"timestamp":"2015-06-15T17:54:36.747Z","level":"INFO","thread":"consumer-deployment-events-1","logger":"forklift.consumer.MyExampleConsumer","message":"My message was: {type=Bat signal, who=Batman}","context":"default"}
You can now go and start playing with your example consumer to make it have different
behavior and sending different types of messages. Try adding an @OnValidate
method
to make sure you have a valid message or change the @Message
property type to an
object and send Json messages instead of k/v pairs.