Das Target ########## Die Klasse, mit der Programmierer am häufigsten arbeiten, ist die **Target**-Klasse. Targets sind die Klassen, die Nachrichten empfangen können. Um das zu ermöglichen, werden sie in der **TargetRegistry** eines Namespaces registriert. Ein Target erhält dabei eine ID, die Target-ID (kurz: **TID**). Man kann den Targets eigene TIDs geben; gewöhnlich reicht jedoch eine von der TargetRegistry generierte zufällige ID. Targets werden bei der Registrierung an einen Thread gebunden. Alle Messages, welche sie im Laufe ihres Lebens erhalten, werden sie immer in demselben Thread erhalten. Es werden niemals Messages zur selben Zeit an das Target gereicht, sondern sie kommen immer nacheinander in die Verarbeitung. Daher braucht man sich hier keine Gedanken um Probleme der Nebenläufigkeit zu machen. Der Aufbau eines Targets ************************ | Ein Target ist irgendeine Klasse, die das ``ITarget``-Interface implementiert. | Besser ist es jedoch, eine Klasse von ``CTarget`` abzuleiten, denn hier ist schon alles Nötige implementiert. Es fehlt lediglich das Anlegen von einem oder mehreren *MessageHandlern*, welche Nachrichten, die an dieses Target gerichtet sind, auffangen und bearbeiten. Ein typisches Target sieht so aus:: class CTestApp extends CTarget { CTestApp() { addMessageHandler(CRecordStartTarget.ID, new CMessageHandler(this, "StartTarget") { @Override public boolean handleMessage(final CEnvelope aEnvelope, final CRecord aRecord) throws Exception { aEnvelope.setResult(null); return true; } }); } } Hier wird im Konstruktor des Objektes ein *Message-Handler* implementiert. Der Konstruktor des Message-Handlers hat zwei Argumente: * Das Target, zu dem er gehört (``this``) * Einen Text, welcher das Loggen von Nachrichten erleichtert (``"StartTarget``) Es ist eine Methode zu implementieren: die ``handleMessage``-Methode, welche die Nachricht erhält. Diese hat auch zwei Argumente: * Den *Envelope*, welcher den Message-Kopf der Nachricht enthält. Hier sind insbesondere die Absender- und Empfänger-Adresse notiert. Zudem enthält er etliche Einstellungen zum Verschicken von Nachrichten. * Den **Record**, welcher die Nutzlast der Nachricht darstellt. Hier ist vor allem die Message-ID zu erwähnen. Beim Hinzufügen eines Message-Handlers zum Target (``addMessageHandler(...)``) ist noch ein wichtiges Argument anzugeben, nämlich die Message-ID. Die Message-ID ist vom Typ ``IId``, und in diesem Fall ist es die *StartTarget*-ID. Diese Nachricht wird als erste vom System an ein neu registriertes Target verschickt, gleichsam als Willkommensgruß. Sie kommt asynchron, d.h. sie wird in dem Thread geliefert, welcher beim Registrieren des Targets angegeben wurde. Alle Nachrichten des Targets werden in diesem Thread abgeliefert, um Probleme mit dem Zugriff auf eigene Daten zu verhindern. Denn wenn alle Nachrichten in demselben Thread geliefert werden, heißt das, dass alle Nachrichten schön hintereinander das Target erreichen. Das Registrieren eines Targets ****************************** Targets werden in der TargetRegistry eines Namespaces registriert:: ITarget myTarget = new CTestTarget(); getNamespace().getTargetRegistry().registerTarget(myTarget, CWellKnownTID.KERNEL); Das Target erhält dabei eine ID, die Target-ID (kurz: **TID**). Alternativ kann man bei der Registrierung eine Wunsch-**TID** mitgeben:: ITarget myTarget = new CTestTarget(); IId myTID = CIdFactory.create(EIdType.STRING, "TEST1"); getNamespace().getTargetRegistry().registerTarget(myTarget, myTID); Gewöhnlich reicht jedoch eine von der TargetRegistry generierte zufällige ID. Wenn der Namespace mehr als einen Thread hat, kann man auch die **Queue-ID** des Threads angeben:: ITarget myTarget = new CTestTarget(); IId myTID = CIdFactory.create(EIdType.STRING, "TEST1"); getNamespace().getTargetRegistry().registerTarget(myTarget, myTID, qid); Die Target Adresse ****************** Jedes Target erhält durch die Registrierung eine eindeutige Adresse. Diese Adressen benutzt man in Nachrichten als Empfänger- und Absenderadresse. Über den Aufbau der Adresse lies :ref:`hier ` weiter. Die Adresse kann man nach der Registrierung des Targets mit ``getAddress()`` holen. Sie ist unveränderlich, kann also weitergegeben werden, ohne dass man befürchten muss, dass sie verändert wird. De-Registrierung **************** Das Target kann jederzeit abgemeldet werden:: 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; } }); Zugriff auf die Umgebung ************************ Innerhalb des Targets kann man leicht auf seine Umgebung zugreifen:: // holt den Kernel getKernel(); // Holt den eigenen Namespace getNamespace(); // Holt die ID des Threads, in dem das Target registriert ist getQueueId(); Convenience-Methoden ******************** Einige Methoden des Targets sind nur der Bequemlichkeit halber vorhanden. Sie rufen dann Methoden des Namespaces bzw, des Kernels auf:: // holt die Slot-Factory; wird mitunter beim Allozieren von Messages benötigt getSlotFactory(); // TimerManager zum Aufziehen von Timern getTimerManager(); // sendet eine Nachricht send(envelope, record); // ebenso send(message); // sendet eine Nachricht zurück, die vorher zurückgestellt wurde sendBack(envelope, record); // ebenso sendBack(message); // sendet eine Notification; eine Antwort wird nicht gewünscht. sendNotification(envelope, record); // ebenso sendNotification(message); // sendet einen Request mit Wunsch auf Antwort sendRequest(envelope, record); // ebenso sendRequest(message); Debugging Tools *************** Einige Methoden erleichtern das Debugging:: // gibt den Simple-Name des Targets zurück (ohne Package) getCurrentName(); // gibt einen eigenen Namen zurück getName(); // prüft, ob Nachrichten, die dieses Target erhält, geloggt werden isVerbose(); // Sollen Nachrichten geloggt werden? setVerbose(boolean);