Messages are always processed by targets. These are classes that implement the ITarget interface or are derived from the CTarget class.

Targets are very lightweight. You are registered in a namespace and receive an ID, the TID, which is unique in this namespace. The registration itself is also very lightweight, so that targets can be created easily and in quantities.

The ID also specifies the address of the target with which it can receive messages. It follows the form TID.NID.NODEID and consists of the target ID (TID), the namespace ID (NID) and the NODE ID for the NODE.

To enable messages to reach the target for processing, you typically register message handlers in the constructor. Any number of message handlers can be added. If a message handler for ID=null is added, it receives all messages that are not explicitly caught.

The first message a target receives is the "CRecordStartTarget" message. In the code, it looks like this:

class CTestApp extends CTarget
        addMessageHandler(CRecordStartTarget.ID, new IMessageHandler()
            public boolean handleMessage(final CEnvelope aEnvelope,
                                         final CRecord aRecord) throws Exception
                return true;

From this point on, the target is registered and can access the environment, e. g. with getKernel() or getNamespace(). Incidentally, the message "StartTarget" is already delivered asynchronously, i. e. in the thread in which the target is registered.

Setting the result to null is helpful to show the caller that no error has occurred. If the message is not processed, the method can return false. The system then enters the error code for NOT_HANDLED. Exceptions during processing are caught, the error code EXCEPTION is entered and the message with exception text is returned. Errors are logged, of course.

By the way, registering a target is just as easy:

final ITarget t1 = new CTestApp();