The Target

The class with which programmers work most often is the Target class. Targets are the classes that can receive messages. To make this possible, they are registered in the TargetRegistry of a namespace. A target receives an ID, the target ID (short: TID). You can give the targets their own TIDs, but usually a random ID generated by the TargetRegistry is sufficient.

Targets are bound to a thread during registration. All messages they receive during their lifetime will always be received in the same thread. Messages are never passed to the target at the same time, but are always processed one after the other. Therefore, there is no need to worry about problems of concurrency.

The Structure of a target

A target is any class that implements the ITarget interface.
However, it is better to derive a class from CTarget, because everything necessary is already implemented here. The only thing missing is the creation of one or more MessageHandlers that capture and process messages addressed to this target.

A typical target looks like this:

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

Here, a message handler is implemented in the constructor of the object. There is a method to implement: the handleMessage method that receives the message. This also has two arguments:

  • The Envelope, which contains the message header of the message. In particular, it contains the sender and recipient addresses. It also contains a lot of meta data which is used for sending messages..
  • The Record, which represents the payload of the message. The message ID should be mentioned here in particular.

When adding a message handler to the target (addMessageHandler (...)) an important argument must be specified, the message ID. The message ID is of type IId, and in this case it is the StartTarget-ID. This message is the first message sent to a newly registered target, as a welcome greeting. It comes asynchronously, i. e. it is delivered in the thread specified when registering the target. All messages of the target are delivered in this thread to prevent problems with accessing your own data.

Registering a Target

Targets are registered in the target registry of a namespace:

ITarget myTarget = new CTestTarget();
getNamespace().getTargetRegistry().registerTarget(myTarget, CWellKnownTID.KERNEL);

The target is given an ID, the target ID (short: TID). Alternatively, you can enter a TID upon registration:

ITarget myTarget = new CTestTarget();
IId myTID = CIdFactory.create(EIdType.STRING, "TEST1");
getNamespace().getTargetRegistry().registerTarget(myTarget, myTID);

Usually, however, a random ID generated by the TargetRegistry is sufficient. If the namespace has more than one thread, you can also specify the Queue ID of the thread:

ITarget myTarget = new CTestTarget();
IId myTID = CIdFactory.create(EIdType.STRING, "TEST1");
getNamespace().getTargetRegistry().registerTarget(myTarget, myTID, qid);

The Target Address

Each target receives a unique address by registration. These addresses are used in messages as recipient and sender addresses.

Read more about the structure of the address here.

The address can be retrieved after registering the target with getAddress().

It is immutable, i. e. it can be passed on without fear of being changed.

Removing a Target

The target can be unregistered at any time:

addMessageHandler(CRecordRequestStopApp.ID, new CMessageHandler(this, "RequestStopApp")
{
    @Override
    public boolean handleMessage(final CEnvelope aEnvelope,
                                 final CRecord aRecord) throws Exception
    {
        deregisterTarget();

        aEnvelope.setResult(null);
        return true;
    }
});

Access To The Environment

Within the target you can easily access your environment:

// Get the kernel
getKernel();

// Get your own namespace
getNamespace();

// Get the ID of the thread in which the target is registered
getQueueId();

Convenience Methods

Some of the target’s methods are only available for convenience. They then call methods of the namespace or kernel:

// fetches the slot factory; sometimes required when allocating messages
getSlotFactory();

// TimerManager for creating timers
getTimerManager();

// sends a message
send(envelope, record);

// sends a message
send(message);

// Returns a message that was previously put on hold
sendBack(envelope, record);

// Returns a message that was previously put on hold
sendBack(message);

// sends a notification; an answer is not desired.
sendNotification(envelope, record);

// sends a notification; an answer is not desired.
sendNotification(message);

// sends a request with request for response
sendRequest(envelope, record);

// sends a request with request for response
sendRequest(message);

Debugging Tools

Some methods make debugging easier:

// returns the simple name of the target (without package)
getCurrentName();

// returns a self-assigned name
getName();

// checks whether messages received by this target are logged
isVerbose();

// If messages should be logged
setVerbose(boolean);