Remote Procedure Calls and the SASS Server

Introduction

It is possible to control a SASS simulation from a programming language other than Java or even remotely over a network. This feature is enabled by the SASS remote procedure call (RPC) server. The idea of the RPC server is simple: it listens on a network port for commands sent by other languages and/or computers. When it receives a command, it performs the requested operation and returns any data that is associated with the command.

For example, after initializing a simulation and starting the server, a Python script on the same PC could adjust the laser power on the simulated microscope. It could then ask the server to simulate five new images and return them to the Python interpreter for further processing.

As another example, a C++ program could run a simulation by connecting to the server remotely over a network. The details of setting up your networked, such as ensuring the correct ports are open in your firewall, are beyond the scope of this documentation.

The RPC service was created using Apache Thrift.

Starting the server

There are three ways to start the server: via the command line, inside the ImageJ GUI, and via a Beanshell script.

Command line

Enter the following command in a console window to start the server from the command line

java -jar PATH_TO_SASS_JAR -r CONFIGURATION_FILE

The above command requires two arguments. PATH_TO_SASS_JAR is the path and name of the SASS .jar file, which can be downloaded from the releases page of the GitHub repository. CONFIGURATION_FILE is a file that specifies the simulation configuration. This file can be created created and saved from inside the SASS ImageJ GUI.

The command will start the server on the default port, which was 9090 at the time of this writing. If instead you wish to specify the port number, use

java -jar PATH_TO_SASS_JAR -p PORT -r CONFIGURATION_FILE

ImageJ

  1. Open the server configuration dialog from the menu bar by clicking Plugins > SASS > Server.
  2. Enter the port number you wish to use for communications with the server. Usually the default (9090) is fine.
  3. Next, you will need a configuration file that defines your simulation parameters. This should be a .sass file containing the simulation details. You can create one by navigating to Plugins > SASS > Simulator, adjusting the simulation parameters as desired, then clicking the Save… button.
  4. Once you have a configuration file, click the Select configuration… button, navigate to your file, and open it.
  5. The Start button should now be enabled. Click it and the simulation will initialize. (This may take a few seconds depending on the size of your simulation.)
  6. When the server has started, you should see the Server running message in the status field.
  7. To stop the server, either click the Stop button or exit the server control window.

If you are using Fiji, then you can see status updates from the server by navigating to Window >> Console on the menu bar.

Beanshell script

There is an example script called example_server.bsh in the scripts folder of SASS that demonstrates how to launch the server through a Beanshell script. After creating a Microscope instance named microscope, simply create and launch the server with these lines

RPCServer server = new RPCServer(microscope, 9090);
server.serve();

Note that you will need to first import RPCServer with the command

import ch.epfl.leb.sass.server.RPCServer;

This code will initialize the server to listen on port 9090 and launch it. If you run the script from the command line, then you can kill the server by typing Ctrl-C.

Server communications

Services

The RPC server works by providing clearly-defined services to clients. Roughly speaking, a service is just a command made by a client that changes the simulation state and/or returns some data. A client must therefore know what services are provided by the server.

The SASS RPC server is implemented using Apache Thrift. The types of services that are provided by the server are defined in the RPCServer.thrift file in the thrift folder of the SASS root directory. Here is what the very first RPCServer.thrift file looked like

namespace java ch.epfl.leb.sass.server
namespace py remotesim

service RemoteSimulationService {

  /**
   * Returns the simulation server's current status.
   */
  string getServerStatus(),

  /**
   * Increments the simulation by one time step and returns an image.
   */
  binary getNextImage(),

  /**
   * Changes the simulation'ss fluorescence activation laser power.
   */
  void setActivationLaserPower(1: double power),

  /**
   * Returns information about the current state of each emitter in
   * a JSON string.
   */
  string getSimulationState()

}

This script defines the package names for the Java and Python code, respectively, and then defines the service that the server provides. There are four method calls:

  1. getServerStatus()
  2. getNextImage()
  3. setActivationLaserPower
  4. getSimulationState

The comments above the method definitions describe what each method does, and the data type that the method returns (string, binary, or void) is specific to Thrift’s IDL language. After this script is compiled by the Thrift compiler into Java and Python code, they are converted into the corresponding data types in each language.

Note that the SASS RPC server sends images as tif-encoded byte strings and the simulation state as JSON strings. You will need to decode this information after its received in your target language.

A Python client

The general problem of setting up a client to interact with the simulation is not so much a SASS problem but is rather more within the scope of working with Apache Thrift. There are many excellent tutorials on their website on how to do this in a number of different languages.

To get you started, we provide here a basic workflow to setup a rudimentary Python client to control a SASS simulation.

  1. Get Apache Thrift.
  2. Navigate into the folder containing the RPCServer.thrift file and open it. Add the namespace for your target lanuage. For Python, this has already been done for you.
  3. Compile the thrift file into Python with the command thrift -r –gen py RPCServer.thrift.
  4. Install the Thrift bindings for Python, preferably inside a virtual environment. pip install thrift
  1. Enter the folder gen-py (or move it to a convenient directory).
  2. Create an emtpy file named client.py.

Inside the client.py file, you will need to add the following code

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from remotesim import RemoteSimulationService
from PIL import Image
from io import BytesIO

def main():
   # Make socket
   transport = TSocket.TSocket('localhost', 9090)

   # Buffering is critical. Raw sockets are very slow
   transport = TTransport.TBufferedTransport(transport)

   # Wrap in a protocol
   protocol = TBinaryProtocol.TBinaryProtocol(transport)

   # Create a client to use the protocol encoder
   client = RemoteSimulationService.Client(protocol)

   # Connect!
   transport.open()

   try:
        x = client.getNextImage()
        img = Image.open(BytesIO(x))
        img.load()
        img.show()
   finally:
        transport.close()

if __name__ == '__main__':
    main()

This will create the client and request the next image from the simulation. By default, the RPC Server will return images as tif-encoded byte strings. You therefore will need the libtiff library in your target language to decode them. In Python, this can be provided by pillow.