Developers guide - Adaptor Management

Overview

This chapter shall give an overview to the adaptor management providing access to adaptors and readers. The behavior of the adaptor management is explained by explaining the most important methods and their behavior.

This includes:

  • error management
  • message management
  • concurrency
  • adaptor management
  • configuration management

Initialization

public boolean initialize(
                String readConfig, 
                String storeConfig,
                boolean commitChanges,
                LLRPExceptionHandler exceptionHandler,
                MessageHandler handler) 
        throws LLRPRuntimeException { ... }

It is very important to initialize the adaptor management properly. For this task the initialize method is provided.

The first two parameters tell the adaptor management where to read or write the configuration.

If you want the adaptor management to run a snapshot configuration set the flag commitChanges to true. If so, all the changes to the adaptors and to the readers in the local adaptors will be reflected immediately back into the configuration file.

The exception handler and the handler are responsible for error and message reporting. If you set them to null you will have to use the corresponding setters to specify them in a later phase.

Shutdown

public synchronized void shutdown() { ... }

If you shutdown your client, it is best to run this method to shutdown the adaptor management. This method performs several cleanup routines, stores the configuration and stops the worker threads.

Definition

public synchronized String define(String adaptorName, String address) 
        throws LLRPRuntimeException, RemoteException, NotBoundException { ... }

In a first step the adaptor management inspects the address parameter. If this parameter is set to null the adaptor is assumed to be a local adaptor. Otherwise the address is considered to be a valid ip address of a remote rmi machine.

In the case where the address is not null the adaptor management tries to establish an rmi connection to the specified ip address and tries to aquire the adaptor from the rmi registry. Please notice that in the remote case the adaptorName you provided will be overridden by the name of the remote adaptor.

Then the management makes sure that in the local repository no other adaptor with the same name exists.

In order to receive asynchronous messages from the adaptor and therefore also from the readers a asynchronous callback receiver has to be installed. The adaptor management uses the class AdaptorCallback for this purpose.

If all the previous steps have been performed successfully a new worker thread is created and started. The thread takes over the control of the adaptor.

Undefinition

public synchronized void undefine(String adaptorName) 
    throws LLRPRuntimeException { ... }

The adaptor management stops the worker thread, deregisters the asynchronous callback and removes the adaptor from the adaptor list.

Enqueuing

public void enqueueLLRPMessage(String adaptorName, 
                       String readerName, 
                       LLRPMessage message) 
                       throws LLRPRuntimeException { ... }

In order to simplify the sending of an LLRPMessage the adaptor management provides a short-cut. When you post an LLRPMessage together with the readerName and the adaptorName the adaptor management will select the correct adaptor and send the message asynchronously to the specified reader. One of the main advantages of this procedure is that you do not have to wait for the message to be sent (Asynchronous messaging).

MessagePosting and Dispatching

Incoming messages are distributed in a publish/subscribe mechanism. Clients interested into a certain message type (or into all messages) can register by means of provided subscription methods. A subscriber needs to implement the interface MessageHandler. The adapter management will then, after a registration, distribute the LLRP messages automatically and asynchronously.

We basically distinguish between full-handlers and partial-handlers.

Full-handler

A full handler receives all incoming messages regardless of their type. Below the available methods are provided:

/**
 * register a handler that will receive all the incoming messages.
 * @param handler the handler.
 */
public void registerFullHandler(MessageHandler handler) { ... }

/**
 * remove a handler from the full handler list.
 * @param handler the handler to be removed.
 */
public void deregisterFullHandler(MessageHandler handler) { ... }

/**
 * tests whether a given handler is already registered or not.
 * @param handler the handler to check for.
 * @return true if the handler is present, false otherwise.
 */
public boolean hasFullHandler(MessageHandler handler) { ...}

Partial-handler

A partial handler receives only a subset of the incoming LLRP messages filtered by the class of the message. At the subscription, the handler can submit a class that hints the adapter management to only deliver the messages that match the the class.

/**
 * register a handler that will receive only a restricted set of messages.
 * @param handler the handler.
 * @param clzz the type of messages that the handler likes to receive (example KEEPALIVE.class).
 */
public void registerPartialHandler(MessageHandler handler, Class clzz) { ... }

/**
 * remove a handler from the handlers list.
 * @param handler the handler to remove.
 * @param clzz the class where the handler is registered.
 */
public void deregisterPartialHandler(MessageHandler handler, Class clzz) { ... }

/**
 * checks whether a given handler is registered at a given selector class.
 * @param handler the handler to check.
 * @param clzz the class where to search for the handler.
 * @return true if the handler is present, false otherwise.
 */
public boolean hasPartialHandler(MessageHandler handler, Class clzz) { ... )

Distribution to the handlers

Whenever a new LLRP message is submitted to the adapter management, the method dispatchHandlers is invoked. All the full-handlers get informed about the new message. Depending on the class, the partial-handlers get retrieved from a lookup-table and then handled in the same way as full-handlers.

Example registration

The registration example below shows, how to register a full handler and a second handler that only retrieves KEEP_ALIVE messages.

// example for a full handler
MessageHandler fullHandler = new MessageHandler() {
        public void handle(String adapter, String reader, LLRPMessage msg) {
                System.out.println(
                        String.format(
                                "received message from adapter: %s, reader: %s",
                                adapter, 
                                reader));
        }
};
AdaptorManagement.getInstance().registerFullHandler(fullHandler);

// example for a partial handler
MessageHandler partialHandler = new MessageHandler() {
        public void handle(String adapter, String reader, LLRPMessage msg) {
                System.out.println(
                        String.format(
                                "received keep-alive message from adapter: %s, reader: %s",
                                adapter, 
                                reader));
        }
};
AdaptorManagement.getInstance().registerPartialHandler(
        partialHandler,
        KEEP_ALIVE.class);

ExceptionPosting

public void postException(
                LLRPRuntimeException e, 
                LLRPExceptionHandlerTypeMap 
                exceptionType, 
                String adapterName, 
                String readerName) 
{ ... }

Whenever an error occurs the clients (adaptors, readers...) can invoke this method. If an exception handler has been installed during setup of the adaptor management, an exception is constructed and is delivered to this exception handler.

In case that the exception handler is not set, an error is reported to the error logger.

LoadFromFile

public synchronized void loadFromFile() 
    throws LLRPRuntimeException { ... }

The adaptor management gives the possiblity to retrieve the adaptors/readers from file. For the storage of the configuration the java.util.Properties are used.

StoreToFile

public synchronized void storeToFile() throws LLRPRuntimeException { ... }

As with loadFromFile this method stores a configuration to a configuration file on disc.

ExceptionHandler

public void setExceptionHandler(LLRPExceptionHandler exceptionHandler) { ... }

In order to receive asynchronous exceptions from the adaptors and the readers you will have to set an exception handler. If you did not set the handler during initialization you can use this helper method to perform this task.

Sample

// create a message handler
MessageHandler msgHandler = new MessageHandler() {
        public void handle(String adapter, String reader, LLRPMessage msg) {
                ...
        }
};

// create an exception handler
ExceptionHandler exHandler = new ExceptionHandler();

// run the initializer method
String readConfig = Utility.findWithFullPath("/readerDefaultConfig.properties");
String writeConfig = readConfig;
boolean commitChanges = true;
AdaptorManagement.getInstance().initialize(
    readConfig, storeConfig, commitChanges, exHandler, msgHandler);

// now the management should be initialized and ready to be used

// create an adaptor
String adaptorName = "myAdaptor";
AdaptorManagement.getInstance().define(adaptorName, "localhost");

// create a reader
String readerName = "myReader";
Adaptor adaptor = AdaptorManagement.getAdaptor(adaptorName);
adaptor.define(readerName, "192.168.1.23", 5084, true, true);

//Enqueue some LLRPMessage on the adaptor
AdaptorManagement.enqueueLLRPMessage(adaptorName, readerName, message);

// when you shutdown your application call the shutdown method
AdaptorManagement.getInstance().shutdown();

Multithreading

The LLRP GUI Client allows several adaptors to be run simultaneously, therefore the AdaptorManagement needs some mechanisms to support a parallel execution of different adaptors.

Each adaptor runs on a thread AdaptorWorker. Each thread maintains a callback for the asynchronous message callback.

 WorkerThread