- Java 11
- Maven 3.6+
The KAR Java SDK provides an implementation of the KAR programming model that utilizes familar Java frameworks such as javax.json. To be complete, the KAR Java SDK must be embedded in a Java middleware framework that provides it with webserver capabilities.
We have two complete implementations of the Java SDK: one based on Open Liberty that supports a more traditional imperative programming style and one based on Quarkus that supports a reactive programming style. You should pick the appropriate KAR Java SDK based on the style of programming (reactive or non-reactive) you wish to adopt in your application code.
The KAR Java SDK is structured internally into three sub-modules:
kar-runtime-core
- Defines the core abstractions of the KAR actor-based programming model in Java and as much as possible of the underlying runtime system that implements it.kar-runtime-liberty
- An implementation of the KAR SDK using Open Liberty as the underlying server framework that provides a fairly traditional Java programming model based on blocking procedure calls and javax.ws.kar-runtime-quarkus
- An implementation of the KAR SDK using Quarkus as the underlying server framework that provides a reactive Java programing model based on the Mutiny and Vertx frameworks that are used by Quarkus.
To use the Java SDK in an application component, you declare a maven
dependency on one of kar-runtime-liberty
or kar-runtime-quarkus
as
described in more detail in the sections below. You then follow the
framework-specific instructions on using annotations and configuration files
to configure your component (eg. by specifying the Actor types).
The developer-facing APIs for the KAR SDK are split between
kar-runtime-core
and kar-runtime-liberty
/kar-runtime-quarkus
.
The primary API is defined by com.ibm.research.kar.Kar
and is specific to the choice of reactive or non-reactive styles.
The primary API is supported by types and annotations
in com.ibm.research.kar.actor
and its sub-packages which is provided by
kar-runtime-core
. The package com.ibm.research.kar.runtime
defines internal APIs that are not intended for developer use; they
are only made public to enable them to be invoked from framework-specific
runtime code found in kar-runtime-liberty
and kar-runtime-quarkus
.
Builds are driven by maven. The basic commmand is mvn install
.
Note: the KAR SDK and example code have been tested using MicroProfile 4.0.1 and the Open Liberty Plugin 3.3 (which pulls v21.0.0.X of openliberty).
The following code examples show how to use the non-reactive Kar SDK.
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonValue;
import static com.ibm.research.kar.Kar.*;
public static void main(String[] args) {
JsonObject params = Json.createObjectBuilder()
.add("number",42)
.build();
JsonValue value = Services.call("MyService", "increment", params);
}
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonValue;
import static com.ibm.research.kar.Kar.*;
public static void main(String[] args) {
JsonObject params = Json.createObjectBuilder()
.add("number",42)
.build();
ActorInstance actor = Actors.ref("ActorType", "ActorID");
JsonValue value = Actors.call(actor, "remoteMethodName", params);
}
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonValue;
import static com.ibm.research.kar.Kar.*;
public static void main(String[] args) {
JsonObject params = Json.createObjectBuilder()
.add("number",42)
.build();
CompletionStage<JsonValue> cf = Services.callAsync("MyService", "increment", params);
JsonValue value = cf
.toCompletableFuture()
.get();
}
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonValue;
import static com.ibm.research.kar.Kar.*;
public static void main(String[] args) {
JsonObject params = Json.createObjectBuilder()
.add("number",42)
.build();
ActorInstance actor = Actors.ref("ActorType", "ActorID");
CompletionStage<JsonValue> cf = Actors.callAsync(actor, "remoteMethodName", params);
JsonValue value = cf
.toCompletableFuture()
.get();
}
The KAR actor runtime allows you to:
- Create an actor using an annotated POJO class
- Execute actors as part of your microservice
KAR requires all Actor classes to implement the ActorInstance interface.
public interface ActorInstance extends ActorRef {
// Allow KAR to get and set session ids
public String getSession();
public void setSession(String session);
// set actor ID and Type
public void setType(String type);
public void setId(String id);
}
The ActorInstance includes two methods to manage session IDs, which KAR uses for actor communications as part of the KAR programming model.
Actor annotations example:
package com.ibm.research.kar.example.actors;
import javax.json.Json;
import javax.json.JsonObject;
import javax.ws.rs.core.Response;
import com.ibm.research.kar.actor.KarSessionListener;
import com.ibm.research.kar.actor.annotations.Activate;
import com.ibm.research.kar.actor.annotations.Actor;
import com.ibm.research.kar.actor.annotations.Deactivate;
import com.ibm.research.kar.actor.annotations.Remote;
@Actor
public class MyActor implements ActorInstance {
@Activate // optional actor constructor
public void init() {
// init code
}
// Expose this method to the actor runtime.
// KAR synchronizes requests to the actor by default
@Remote
public void updateMyState(JsonObject json) {
// remote code
}
// Expose this method to the actor runtime.
// KAR synchronizes requests to the actor by default
@Remote
public String readMyState() {
// read-only code
}
// methods not annotated as @Remote are
// not callable by actor runtime
public void cannotBeInvoked() {
}
@Deactivate // optional actor de-constructor
public void kill() {
}
//.... ActorInstance implementation would be below
//.....
}
In addition to writing the framework independent application code using the KAR SDK, you will need to write some additional bits of boilerplate to enable Open Liberty to execute your component.
- You will need to add a stanza to your
pom.xml
to declare a dependency onkar-runtime-liberty
and on some Open Liberty dependencies used within KAR. You will also need to include theliberty-maven-plugin
andmaven-war-plugin
to your build plugins. - You will need to provide a Java class that extends
javax.ws.rs.core.Application
. - If your application component contains any KAR Actor types, you
will need to specify them in your
web.xml
by providing values for thekar-actor-classes
andkar-actor-types
context params.
For an automatically tested and complete example of doing this, you should consult actors-dp-java. In particular model your configuration on pom.xml and web.xml.
The following code examples show how to use the reactive Kar Java SDK.
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonValue;
import static com.ibm.research.kar.Kar.*;
import io.smallrye.mutiny.Uni;
public static void main(String[] args) {
JsonObject params = Json.createObjectBuilder()
.add("number",42)
.build();
Uni<JsonValue> uni = Services.call("MyService", "increment", params);
uni.chain(value -> {
// Do something with the returned value and produce the next Uni
}).chain(value2 -> {
...
}
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonValue;
import static com.ibm.research.kar.Kar.*;
import io.smallrye.mutiny.Uni;
public static void main(String[] args) {
JsonObject params = Json.createObjectBuilder()
.add("number",42)
.build();
ActorInstance actor = Actors.ref("ActorType", "ActorID");
Uni<JsonValue> uni = Actors.call(actor, "remoteMethodName", params);
uni.chain(value -> {
// Do something with the result of the call and produce the next Uni
}).chain(value2 -> {
...
}
The KAR actor runtime allows you to:
- Create an actor using an annotated POJO class
- Execute actors as part of your microservice
KAR requires all Actor classes to implement the ActorInstance interface.
public interface ActorInstance extends ActorRef {
// Allow KAR to get and set session ids
public String getSession();
public void setSession(String session);
// set actor ID and Type
public void setType(String type);
public void setId(String id);
}
The ActorInstance includes two methods to manage session IDs, which KAR uses for actor communications as part of the KAR programming model.
Actor annotations example:
package com.ibm.research.kar.example.actors;
import javax.json.Json;
import javax.json.JsonObject;
import com.ibm.research.kar.actor.annotations.Activate;
import com.ibm.research.kar.actor.annotations.Actor;
import com.ibm.research.kar.actor.annotations.Deactivate;
import com.ibm.research.kar.actor.annotations.Remote;
@Actor
public class MyActor implements ActorInstance {
@Activate // optional actor constructor
public Uni<Void> init() {
// init code
}
// Expose this method to the actor runtime.
// KAR synchronizes requests to the actor by default
@Remote
public Uni<Void> updateMyState(JsonObject json) {
// remote code
}
// Expose this method to the actor runtime.
// KAR synchronizes requests to the actor by default
@Remote
public Uni<String> readMyState() {
// read-only code
}
// methods not annotated as @Remote are
// not callable by actor runtime
public void cannotBeInvoked() {
}
@Deactivate // optional actor de-constructor
public Uni<void> kill() {
}
//.... ActorInstance implementation would be below
//.....
}
In addition to writing the actual application code using the KAR SDK, you will need to write some additional bits of configuration to enable Quarkus to execute your component.
- You will need to add a stanza to your
pom.xml
to declare a dependency onkar-runtime-core
,kar-runtime-quarkus
and on some Quarkus dependencies used within KAR. You will also need to add thequarkus-maven-plugin
andmaven-surefire-plugin
to your build plugins. - If your application component contains any KAR Actor types, you
will need to specify them in your
application.properties
by providing values forkar.actors.type
andkar.actors.classes
.
For an automatically tested and complete example of doing this, you should consult actors-dp-java-reactive. In particular model your configuration on pom.xml and application.properties.