aktrs 1.3 user guide

updated on 8 Aug 2016 by Raffaele Arecchi


aktrs is a Java application library implementing the Actor Model. It provides remote actors through TCP sockets (and SSL sockets), actor profiling, a Console and tunable logging. It's API is easy to use and its core is written in few lines of source code.

aktrs requires Java version 1.5 or newer, has no additional dependencies and can be packaged into any application according to its LGPL license.

The README file inside the distributed package contains a brief description of the library with the Release Notes for the changes contained in this version.

Contents:

  1. What actors are
  2. A bit of aktrs ontology
  3. Getting started with actors
  4. Actors adresses
  5. Building an ActorSystem
  6. Summoning actors
  7. Actor initialization
  8. Telling messages
  9. Customizing mailbox capacity
  10. Processing messages
  11. Stopping actors
  12. Shutting down the ActorSystem
  13. Remote systems and remote actors
  14. Enabling SSL
  15. Logging
  16. Profiling
  17. More examples
  18. Console

1. What actors are

Actors are independent entities which communicate by sending messages to each other and which, in response to the messages they receive, are able to make decisions, perform elaborations, send messages to other actors and eventually creating new actors.
Designing a software with actors could add complexity to the domain the software models, but with the advantage to have clear, understandable and testable components especially when the domain relates to high concurrent environments.

2. A bit of aktrs ontology

Actors are objects that operate independently and in parallel. An actor communicate to another actor by sending, or telling, it a message to its mailbox. A mailbox is a container of messages ordered by delivery time (also known as first-in-first-out queue). An actor waits while its mailbox is empty, otherwise it picks the oldest message, performs behavior related to that message, and repeats this sequence as long as the mailbox is not empty.
An actor system, or simply system, is a container of actors and is able of summoning, meaning creating new actors or new references to existing ones.
An actor is said to belong to a system if that system contains the actor.
Actors can be told to stop by any actor, causing its remotion from its actor system.
Two systems can be linked togheter. A system is able to summon any actor on any linked system.
An actor is said to be local or remote relative to a system. An actor is local to a system if it belongs to that system. An actor is remote to a system A if it belongs to another system B which is linked to A. Any actor can tell messages to any local or remote actor.
An actor is operative if it is ready to process messages from its mailbox, otherwise it is not operative.

3. Getting started with actors

The main entities are instances of the aktrs.rt.ActorSystem and aktrs.rt.Actor classes. An ActorSystem is a container of actors and is responsible for their life-cycle management. An actor is implemented as an instance of the Actor class. The Actor class is expected to be sub-classed to provide custom actor behavior.

To create a custom actor class, just extends Actor overriding the Actor.onMessage(Object message, Actor sender) method with the desired behavior:

import aktrs.rt.Actor;

public class HelloActor extends Actor {
  @Override
  protected void onMessage(Object message, Actor sender) {
    System.out.println("Hello " + message.toString());
  }
}

To use this actor, we need to "summon" it through method ActorSystem.summon(String actorAddress, Class<? extends Actor> klass) .
In the example below we let an "empty" actor send two messages to an HelloActor by the instance method Actor.tell(Object message, Actor recipient) , then we finally shutdown the ActorSystem :

import java.util.logging.Level;
import aktrs.rt.Actor;
import aktrs.rt.ActorSystem;

public class HelloTest {

  public static void main(String[] args) {
    ActorSystem sys = new ActorSystemBuilder("my-sys").build();
    sys.setLogLevel(Level.FINE);

    Actor callerActor = sys.summon("/my-sys/caller", Actor.class);
    Actor helloActor = sys.summon("/my-sys/hello-actor", HelloActor.class);
    
    callerActor.tell(helloActor, "John");
    callerActor.tell(helloActor, "Tim");
    
    sys.shutdown("finished");
  }
}

which logs on the standard output:

28-07-2016 17:05:25.073-[main                                              ]-1-[aktrs.rt.ActorSystemBuilder.build]-Actor System my-sys started.
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.ActorSystem.summon]-Actor System my-sys. Summoning  /my-sys/caller, Class:  aktrs.rt.Actor, Initialization object: null
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.ActorSystem.summon]-Actor System my-sys. Actor /my-sys/caller is a local actor
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.ActorSystem.summon]-Actor System my-sys. Actor /my-sys/caller summoned
28-07-2016 17:05:25.089-[/my-sys/caller                                    ]-13-[aktrs.rt.Actor.run]-Starting Actor /my-sys/caller
28-07-2016 17:05:25.089-[/my-sys/caller                                    ]-13-[aktrs.rt.Actor.run]-Actor /my-sys/caller, mail box capacity: -1
28-07-2016 17:05:25.089-[/my-sys/caller                                    ]-13-[aktrs.rt.Actor.run]-Actor /my-sys/caller is operative
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.ActorSystem.summon]-Actor System my-sys. Summoning  /my-sys/hello-actor, Class:  HelloActor, Initialization object: null
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.ActorSystem.summon]-Actor System my-sys. Actor /my-sys/hello-actor is a local actor
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.ActorSystem.summon]-Actor System my-sys. Actor /my-sys/hello-actor summoned
28-07-2016 17:05:25.089-[/my-sys/hello-actor                               ]-14-[aktrs.rt.Actor.run]-Starting Actor /my-sys/hello-actor
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.Actor.receiveTell]-Actor /my-sys/caller telling to a local Actor /my-sys/hello-actor
28-07-2016 17:05:25.089-[/my-sys/hello-actor                               ]-14-[aktrs.rt.Actor.run]-Actor /my-sys/hello-actor, mail box capacity: -1
28-07-2016 17:05:25.089-[/my-sys/hello-actor                               ]-14-[aktrs.rt.Actor.run]-Actor /my-sys/hello-actor is operative
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.Actor.receiveTell]-Actor /my-sys/caller telling to a local Actor /my-sys/hello-actor
28-07-2016 17:05:25.089-[/my-sys/hello-actor                               ]-14-[aktrs.rt.Actor.run]-Actor /my-sys/hello-actor, received message. Sender: /my-sys/caller , message: John
28-07-2016 17:05:25.089-[main                                              ]-1-[aktrs.rt.Actor.receiveTell]-Actor /my-sys/system telling to a local Actor /my-sys/system
28-07-2016 17:05:25.089-[/my-sys/system                                    ]-11-[aktrs.rt.Actor.run]-Actor /my-sys/system, received message. Sender: /my-sys/system , message: {stop: finished}
28-07-2016 17:05:25.089-[/my-sys/system                                    ]-11-[aktrs.rt.Actor.run]-Actor /my-sys/system is no more operative
Hello John
28-07-2016 17:05:25.089-[/my-sys/system                                    ]-11-[aktrs.rt.ActorSystem.internalShutdown]-Shutting down Actor System my-sys : finished
28-07-2016 17:05:25.089-[/my-sys/hello-actor                               ]-14-[aktrs.rt.Actor.run]-Actor /my-sys/hello-actor, received message. Sender: /my-sys/caller , message: Tim
Hello Tim
28-07-2016 17:05:25.104-[/my-sys/system                                    ]-11-[aktrs.rt.Actor.receiveTell]-Actor /my-sys/system telling to a local Actor /my-sys/caller
28-07-2016 17:05:25.104-[/my-sys/system                                    ]-11-[aktrs.rt.Actor.receiveTell]-Actor /my-sys/system telling to a local Actor /my-sys/monitor
28-07-2016 17:05:25.104-[/my-sys/caller                                    ]-13-[aktrs.rt.Actor.run]-Actor /my-sys/caller, received message. Sender: /my-sys/system , message: {stop: finished}
28-07-2016 17:05:25.104-[/my-sys/monitor                                   ]-12-[aktrs.rt.Actor.run]-Actor /my-sys/monitor, received message. Sender: /my-sys/system , message: {stop: finished}
28-07-2016 17:05:25.104-[/my-sys/system                                    ]-11-[aktrs.rt.Actor.receiveTell]-Actor /my-sys/system telling to a local Actor /my-sys/hello-actor
28-07-2016 17:05:25.104-[/my-sys/monitor                                   ]-12-[aktrs.rt.Actor.run]-Actor /my-sys/monitor is no more operative
28-07-2016 17:05:25.104-[/my-sys/caller                                    ]-13-[aktrs.rt.Actor.run]-Actor /my-sys/caller is no more operative
28-07-2016 17:05:25.104-[/my-sys/hello-actor                               ]-14-[aktrs.rt.Actor.run]-Actor /my-sys/hello-actor, received message. Sender: /my-sys/system , message: {stop: finished}
28-07-2016 17:05:25.104-[/my-sys/hello-actor                               ]-14-[aktrs.rt.Actor.run]-Actor /my-sys/hello-actor is no more operative

The logs show the asynchronous nature of the system in which the actors operate independently.
Notice also that the call to ActorSystem.shutdown(String reason) could happen before the messages are actually processed; the reason why here the actor continues to process is because the shutdown actually send Stop messages (more on the semantic of shutdown in Stopping actors).
The logs also shows two other actors, named /my-sys/system and /my-sys/monitor : these are internal actors used by the system for custom features and profiling.
The ActorSystem is instantiated with an ID my-sys . While not necessary for this example, the ID is important when other remote ActorSystem s must be connected togheter (linked) and be identifiable by themselves.
Two Actor s with addresses /my-sys/caller and /my-sys/hello-actor are summoned specifying their real type Actor and HelloActor respectively. The system ID in the address string is not superfluous, in fact every ActorSystem is able to summon any actor on any remote linked ActorSystem .
By Actor.tell(Object message, Actor recipient) , the actor /my-sys/caller sends to /my-sys/hello-actor the messages (in this case strings) "John" and "Tim".
By the overridden Actor.onMessage(Object message, Actor sender) , the actor /my-sys/hello-actor carries out its job printing a greeting message on the standard output.

A final important remark for this example is that these actors are controlled by the main thread which executes the tells on its own. In general, this is an incorrect way to design an actor application as the actors should be autonomous about telling and doing any kind of thing. For this reason, the library provides a ActorSystem.tick(ActorAddress) method by which an external thread can interact with the actor system.
Thus the previous code can be made cleaner with:

import java.util.logging.Level;
import aktrs.rt.Actor;
import aktrs.rt.ActorSystem;

public class HelloTest {

  public static void main(String[] args) {
    ActorSystem sys = new ActorSystemBuilder("my-sys").build();
    sys.setLogLevel(Level.FINE);
    sys.summon("/my-sys/caller", MainActor.class);
    sys.tick("/my-sys/caller");
  }

  public static class MainActor extends Actor {
    @Override
    protected void onTick() {
      Actor helloActor = summon("/my-sys/hello-actor", HelloActor.class);
      tell(helloActor, "John");
      tell(helloActor, "Tim");
      shutdown("finished");
    }
  }
}	

4. Actor addresses

Every actor has an address. This address is specified by the string /system-id/actor-name . The beginning and the second slashes in the address are mandatory, their mean is to identify the ActorSystem ID which manages the actor. For this reason a system ID could be any sequence of characters but must not contain any slash. The actor name instead may contain any characters including slashes.
The internal representation of an actor address is realized by class aktrs.rt.ActorAddress . The constructor of this class admits a valid address as string and will throw a RuntimeException if the address is not admissible.
Most of the API in aktrs provides method versions with addresses both in String and ActorAddress formats.

5. Building an ActorSystem

The appropriate class for building an actor system is aktrs.rt.ActorSystemBuilder .
Its constructor gets the ID of the ActorSystem to generate and provides the following methods for configuration (refer to section Remote systems and remote actors for TCP parameters):

All this methods return the instance of the ActorSystemBuilder to let the API be fluent, finally the ActorSystemBuilder.build method takes care of setting up the new actor system.
The following is an example of use:

ActorSystem sys = new ActorSystemBuilder("sys")
                   .withPort(9002)
                   .withSSL(true)
                   .withServerThreadPoolSize(50)
                   .build();

6. Summoning actors

To create an actor or to get a reference to an existing one, the ActorSystem class provides the following instance methods:

All of these accept the address both in String or in ActorAddress format and return the summoned actor instance.
The first two methods are often used when it is certain that an actor already exists at the provided address. Of course if no actor is registered with that address, a new one is created.
The methods providing the class input are able to summon an actor of the type specified. If an actor is already registered at the specified address, the class type input has no effect.
The last of them provide an optional initial object input, used by the actor in the initialization phase.

The summoning of an actor consists of the following steps:

The Thread associated to the summoned actor execute these tasks:

  1. initializes the actor mailbox with a java.util.concurrent.LinkedBlockingQueue for the messages,
  2. if an initObj was provided, executes method Actor.init(Object initObj) (see Actor initialization),
  3. makes the actor operative,
  4. begins to consume synchronously the messages inside its mailbox.

All of the summoning methods of the ActorSystem class are replicated into the aktrs.rt.Actor class for simpler coding. They just redirect to the before mentioned summon methods.

7. Actor initialization

Initialization is performed by Actor.init(Object initObj) . The default implementation does nothing, so to customize initialization an override of the method must be implemented.

An example of custom initialization is the following, where an address of an actor is passed as initialization object and the reference to that actor is stored inside a field:

import aktrs.rt.Actor;
import aktrs.rt.ActorAddress;

public class HelloActor extends Actor {
  private Actor forwardActor;

  @Override
  protected void init(Object initObj) {
    forwardActor = summon((ActorAddress) initObj);
  }

  @Override
  protected void onMessage(Object message, Actor sender) {
    tell(forwardActor, "Hello " + message.toString());
  }
}	

Hence the behavior of this actor is to forward a greeting message to another actor.

If a java.lang.Exception is thrown while initializing, the actor will go to a non operative state and its associated Thread terminates.

8. Telling messages

Telling a message to another actor is performed by the instance method Actor.tell(Object message, Actor recipient) .
Calling this method is blocking until the message is successfully delivered to the recipient actor's mailbox. The method returns as soon as the message is on the recipient mailbox, therefore from an actor perspective the call may be seen as asynchronous.

If the recipient actor is not operative, the delivery is delayed to a maximum time of 1000 milliseconds (1 second), after which if the recipient is still not operative a java.lang.RuntimeException is thrown.
The reason for this retry is because the actor could be not operative during its initialization phase.

This example shows an "echo actor" which tells to the caller the same message:

import aktrs.rt.Actor;

public class EchoActor extends Actor {
  @Override
  protected void onMessage(Object message, Actor sender) {
    tell(sender, message);
  }
}	

9. Customizing mailbox capacity

The Actor class implements its mailbox as an unbounded java.util.concurrent.LinkedBlockingQueue . It is possible to define a maximum capacity for the mailbox overriding Actor.mailboxCapacity() .

In the example below the capacity is set to 1000:

import aktrs.rt.Actor;

public class HelloActor extends Actor {
  @Override
  protected int mailboxCapacity() {
    return 1000;
  }

  @Override
  protected void onMessage(Object message, Actor sender) {
    System.out.println("Hello " + message.toString());
  }
}	

Every Actor.tell method call to an actor with a full bounded-capacity mailbox is blocking until the mailbox will be freed to accommodate new incoming messages.
It is not possible to change the capacity of the mailbox once it is initialized.

Fixed mailbox capacity is useful in high-throughput contexts where memory consumption must be controlled and actor processing time is slow or uncertain.

10. Processing messages

An actor processes the messages from its mailbox once at a time by method Actor.onMessage(Object message, Actor sender) . The classes extending Actor are expected to override this method to accomplish their purpose.

If an Exception is raised while processing a message, method onProcessingError(Exception e, Object message, Actor sender) is called. Actor classes should override this method if custom operations are needed. An exception raised while processing a message does not cause an actor to stop nor its associated thread to die, instead the actor will continue to process messages from its mailbox.

Here an example of an actor who computes squares, complaining with the sender actor if the message is not an Integer :

import aktrs.rt.Actor;

public class SquareActor extends Actor {
  @Override
  protected void onMessage(Object message, Actor sender) {
    Integer value = (Integer) message;
    System.out.println("Square of " + value + " is " + value * value);
  }

  @Override
  protected void onProcessingError(Exception e, Object message, Actor sender) {
    if (e instanceof ClassCastException) {
      tell(sender, "Cannot compute square of " + message + "!!!");
    }
  }
}	

11. Stopping actors

Every actor can stop another actor by sending it an aktrs.messages.Stop message. Below an example of an actor who stops who tells it a message:

import aktrs.messages.Stop;
import aktrs.rt.Actor;

public class KillerActor extends Actor {
  @Override
  protected void onMessage(Object message, Actor sender) {
    tell(sender, Stop.create("no real reason"));
  }
}	

Upon receiving a Stop the actor:

  1. clears its mailbox,
  2. puts itself in not operative state,
  3. unregister itself from the ActorSystem to which it belongs,
  4. calls Actor.manageStop(Stop message).

The method Actor.manageStop is designed to be overridden if further specific stop processing is needed.

The Actor class provides two shortcuts to stop an actor:

The previous actor can be rewritten shortly:

import aktrs.messages.Stop;
import aktrs.rt.Actor;

public class KillerActor extends Actor {
  @Override
  protected void onMessage(Object message, Actor sender) {
    stop(sender, "no real reason");
  }
}	

12. Shutting down the ActorSystem

Shutdown the system with one of the following method in ActorSystem :

Both will stop all local actors and close all opened resources. To shutdown a linked ActorSystem see Remote systems and remote actors.

Another way to shutdown is done by sending a Stop message to the system actor:

import aktrs.messages.Stop;
import aktrs.rt.Actor;
import aktrs.rt.ActorSystem;

public class Test {
  public static void main(String[] args) {
    ActorSystem mySystem = new ActorSystemBuilder("my-sys").build();
    Actor systemActor = mySystem.summon("/my-sys/system");
    systemActor.tell(systemActor, Stop.create("time to die"));
  }
}	

13. Remote systems and remote actors

When two ActorSystem s are linked togheter, all their actors can communicate each other by sending messages and even summoning actors on the linked system. Linking is actually implemented by TCP socket connections. There is no limit to how many systems can be linked togheter. To let an ActorSystem be linkable, it must be built with a listening port.

Running a remote system is simple as to run this class:

import aktrs.rt.ActorSystem;

public class RemoteSys {
  public static void main(String[] args) {
    new ActorSystemBuilder("remote-sys").withPort(9002).build();
  }
}	

This new system remote-sys will accept TCP connections to port 9002. No other work is needed to do here: summoning, sending messages, shutting down and all operations can be done by a remote linked system.
A deployment pattern could be: run this class as a single JVM process on any machine, then run the actual software only on one system who will orchestrate everything. Of course, if changes to Java code are made, a full restart must be done as dynamic class loading is not internally implemented (but you can implement it on your own).

This example class, which we run on the same machine, shows a linking of the previous system, a remote summon, a remote tell and a remote stop:

import java.net.InetAddress;
import java.net.UnknownHostException;
import aktrs.messages.Stop;
import aktrs.rt.Actor;
import aktrs.rt.ActorSystem;

public class Main {
  public static void main(String[] args) throws UnknownHostException {
    ActorSystem system = new ActorSystem("main-sys").withPort(9001).build();
    String remoteId = system.link(InetAddress.getLocalHost(), 9002);
    Actor remoteActor = system.summon("/" + remoteId + "/remote-actor", Actor.class);
    Actor systemActor = system.summon("/main-sys/system");
    systemActor.tell(remoteActor, "Hello!");
    systemActor.tell(remoteActor, Stop.create("time to die"));
  }
}	

Linking is done by instance method ActorSystem.link(InetAddress netAddress, int port) which returns the remote system ID once successfully connected. Runtime exceptions could be raised on IO problems or if the linked systems share the same ID. If the discovered ActorSystem has ID of an already linked one, disconnection of the old system is performed. Once linked, TCP connection is automatically managed by the library.
If an ActorSystem A become linked to an ActorSystem B then automatically B will be linked to A. When the two systems are linked, communication between them can occurs on separate sockets depending on the kind of operations.

All tells to a remote actor must send a java.io.Serializable message. If the message is not serializable, a RuntimeException will occur.

A remote shutdown is not possible, instead send a Stop message to the actor system belonging to the remote ActorSystem .

Internally, the reference to an Actor which belongs to a linked remote ActorSystem is implemented in aktrs with a proxy/mirror ( aktrs.rt.RemoteActor ), so that all remote operations are actually redirected. aktrs automatically manages the creation of these proxies so that working with remote actors is transparent inside code.

Unlinking from a remote system is performed by the instance method ActorSystem.unlink(String remoteSystemId) .

14. Enabling SSL

To enable SSL for accepting secure connections, build the actor system by ActorSystemBuilder.withSSL setting the value to true . All incoming socket connections will be created through a javax.net.ssl.SSLServerSocketFactory .

It is responsibility of the programmer to set up appropriate certificates and run the JVMs with those ones enabled.
To configure SSL, please refer to the documentation of the keytool utility provided by the JDK.

Finally, consider that SSL is enabled on the socket accepting connections. This means that remote ActorSystem could or could not provide SSL as communication occurs on separate sockets depending on the kind of operations (refer to Remote systems and remote actors). So mixed secure/unsecure environments are possible.

15. Logging

By default, the ActorSystemBuilder instantiate a java.util.logging.Logger with a Level.INFO and printing to the standard output, precisely using a aktrs.util.ConsoleOutputHandler with formatter aktrs.util.AktrsFormatter .

To provide a custom java.util.logging.Logger , ActorSystemBuilder provides a method withLogger(Logger logger) .

Change of logging level at runtime may be accomplished by method ActorSystem.setLogLevel(Level newLevel) or by telling an aktrs.messages.LogLevelMessage to the system actor.

16. Profiling

Processing data time can be collected from any actor. For this purpose, the monitor actor with address /system-id/monitor is responsible to manage profiling for all actors belonging to system-id.

An actor can be told to enable/disable profiling by telling a aktrs.messages.ToggleProfilingMessage to the monitor actor of the system to which it belongs. This is accomplished by setting the property mode of the message to aktrs.messages.ProfilingMode.ON / aktrs.messages.ProfilingMode.OFF respectively.

To get the average processing time of an actor, i.e. the mean time of all processing times for Actor.onMessage , send to the monitor a message aktrs.messages.AverageProcessingTimeRequest with field replyTo compiled with the address of the actor who will receive the report data aktrs.messages.AverageProcessingTimeResponse .
Average processing time che also be requested only for a specific class of messages: the request is a message aktrs.messages.AverageProcessingTimeByClassRequest whose field replyTo is compiled as before and field klass is compiled with the class instance of the messages argument of the request: in this case the report is a aktrs.messages.AverageProcessingTimeByClassResponse . aktrs.messages.ToggleProfilingMessage is instantiated with the following parameters also, which are related to flow metrics data collection (see below):

Parameter name Type Default Description
flowMetricsPrecision long 1000 Specify the time interval (milliseconds) by which collect flow metrics
flowMetricsRetention long 2 Specify the maximum number of time intervals which collect the flow metrics

If profiling is enabled, after every interval time specified by flowMetricsPrecision the actor collects some metrics about processing time, idle time and queue sizes, and the information gathered is finalized into a aktrs.messages.FlowMetric described by (start-time and end-time are defined by milliseconds from 1 Gen 1970):

Parameter name Type Description
startInterval long The start-time of the interval
startQueueSize long The size of the mailbox at start-time of the interval
elapsedWorkTime long The processing-time (non-idle state) in the interval, partial result if the collection of this metric is not completed
endInterval long The end-time of the interval, -1 if the collection of this metric is not completed
endQueueSize long The size of the mailbox at end-time of the interval, -1 if the collection of this metric is not completed

The numbers of maximum collected metrics is defined by flowMetricsRetention , after which the oldest metrics are discarded.

To request the metrics, send to the monitor a aktrs.messages.FlowMetricsRequest with field replyTo compiled with the address of the actor who will receive the report data aktrs.messages.FlowMetricsResponse . The response is filled with the mailbox capacity, with the flowMetricsPrecision, with the metrics collection time and with a list of aktrs.messages.FlowMetric which collects the metrics on time intervals ordered by the oldest to the most recent.

17. More examples

The source package of this software includes the source code for tests under directory src/test . These tests may be useful as examples.
The package aktrs.test.local.scenario contains the following JUnit test classes:

18. Console

The library provides a console, which itself is implemented by two actors ( aktrs.console.ConsoleActor and aktrs.console.ConsoleInputActor ).

Running the console is as simple as running the jar itself:

# java -jar aktrs-1.3.jar consolesys 8473 false
aktrs version 1.3
/consolesys/console :8473 > summon /consolesys/hello akstr.rt.Actor
akstr.rt.Actor
/consolesys/console :8473 > tell /consolesys/hello Hello world!
Sent message: Hello world!
/consolesys/console :8473 > list consolesys
Sent list actor message: aktrs.messages.ListActorsRequest{systemId: consolesys|reply address: /consolesys/console}
/consolesys/console
/consolesys/console-input
/consolesys/hello
/consolesys/monitor
/consolesys/system

/consolesys/console :8473 > stop /consolesys/hello
Sent message: {stop: stop from console}
/consolesys/console :8473 > quit
Bye.
#	
In the example above the console runs an actor system with id consolesys , accepting remote connections to the 8473 port and without SSL (false).
After, we summon an actor /consolesys/hello and tell it a message "Hello world!".
Then a list command is requested asking for the addresses of all the actors belonging to consolesys .
Finally we send a stop to /consolesys/hello and the quit command takes us back to the OS shell.

The console is an actor system designed to connect to remote actor systems and send messages, summoning, monitoring, or managing them.
Typing the help command, we get a summary for all available commands:

/consolesys/console :8473 > help
average-processing-time
	Usage: average-processing-time [profiled actor address]
	Description: Returns the average processing time for the specified profiled actor
average-processing-time-by-class
	Usage: average-processing-time-by-class [profiled actor address] [class of messages to get average time processing]
	Description: Returns the average processing time for the specified class of messages and for the specified profiled actor
exit
	Usage: exit | quit
	Description: Quit the console
flow-metrics
	Usage: flow-metrics [profiled actor address]
	Description: Returns the average processing time for the specified profiled actor
help
	Usage: help
	Description: describes all available commands for the console
link
	Usage: link [host address] [port]
	Description: Link to the actor system listening to the specified address and the specified port
list
	Usage: list [actor system id]
	Description: Returns the list of actor addresses for the given actor system
log
	Usage: log [actor system id] [log level (SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST)]
	Description: Change log level of the specified actor system to the specified level
profile
	Usage: profile [on|off] [profiled actor address] [flow metric precision] [flow metric retention]
	Description: Enable/disable profiling for the specified actor, with integer time precision and retention parameters
quit
	Usage: exit | quit
	Description: Quit the console
realtime-monitor
	Usage: realtime-monitor [poll time in milliseconds] [one or more profiled actor address]
	Description: Enter to real time monitoring of actor profiling data
stop
	Usage: stop [actor address]
	Description: Send a Stop message to the specified actor
summon
	Usage: summon [actor address] [full class name]
	Description: Summon an actor with the specified address and the specified class
tell
	Usage: tell [actor address] [string message]
	Description: Tell the specified UTF-16 string message to the specified actor
tick
	Usage: tick [actor address]
	Description: Send a tick to the specified actor
unlink
	Usage: unlink [remote actor system id]
	Description: unlink the specified remote actor system
version
	Usage: version
	Description: Print the version of the current console

/consolesys/console :8473 >	

Author: Raffaele Arecchi. Contact the author of this document via mail to: raffaele.arecchi {at}gmail{point}com
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.