Eine dritte Message



Ein Target, welches sich selbst eine Message zuschickt (Version 3).

Nun werden wir eine Message mit Daten versenden. Das machen wir jetzt erst einmal umständlich - zu Fuß sozusagen.

final class CTarget004 extends CTarget
{
    private static final IId TESTID = CIdFactory.create(3333);

    private static final UUID KEYID003 = UUID.fromString("7b3fbd19-5327-48da-8b92-3f0bedd16624");

    private static final short SHORT23 = (short) 23;
    private static final short SHORT99 = (short) 99;
    private static final short SHORT04 = (short) 04;
    private static final short SHORT31000 = (short) 31000;
    private static final int INT67000 = 67000;
    private static final String MARY_ANN = "Mary Ann";

    CTarget004()
    {
        //
        // The first message get we always directly after the registration of the target.
        //
        addMessageHandler(CRecordStartTarget.ID, new IMessageHandler()
        {
            @Override
            public boolean handleMessage(final CEnvelope aEnvelope,
                                         final CRecord aRecord) throws Exception
            {
                // means success
                aEnvelope.setResult(null);

                handmadeTriggerWithData(MARY_ANN, INT67000, new short[] { SHORT04, SHORT23, SHORT99, SHORT31000 });

                // means we have consumed this message
                return true;
            }

        });


        // catch the message for me.
        addMessageHandler(TESTID, new IMessageHandler()
        {
            @Override
            public boolean handleMessage(final CEnvelope aEnvelope,
                                         final CRecord aRecord) throws Exception
            {
                CConstants.LOG.debug(aRecord.getId().toString());

                // get data from the first slot
                // not funny: we have to know the slot key to fetch our data
                ISlot slot = aRecord.getSlot(1);
                CConstants.LOG.debug("String is {}", slot.getValue());

                // get data from the second slot
                slot = aRecord.getSlot("SillySlotKey");
                CConstants.LOG.debug("Integer is {}", slot.getValue());

                // get data from the third slot
                slot = aRecord.getSlot(KEYID003);
                // Not funny: a cast is necessary
                final short[] value = (short[]) slot.getValue();
                final String valueStr = Arrays.toString(value);
                CConstants.LOG.debug("ShortArray is {}", valueStr);

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

    protected void handmadeTriggerWithData(final String aName,
                                           final int aInt,
                                           final short[] aShortArray) throws CException
    {
        final CEnvelope env = new CEnvelope(getAddress());

        final CRecord rec = new CRecord(TESTID);

        // put a String
        ISlot slot = CSlotFactoryHelper.create(CCommonSlotType.STRING, aName);
        // we use an integer as slot key
        rec.addSlot(1, slot);

        // put an integer
        slot = CSlotFactoryHelper.create(CCommonSlotType.INT, aInt);
        // we use a String as slot key
        rec.addSlot("SillySlotKey", slot);

        // put a short array
        slot = CSlotFactoryHelper.create(CCommonSlotType.SHORTARRAY, aShortArray);
        // we use am UUID as slot key
        rec.addSlot(KEYID003, slot);

        sendNotification(env, rec);
    }
}

Zuerst schauen wir uns das Senden der Message an. An der Erstellung des Envelopes und des Records ändert sich nichts. Anschließend werden die Daten in die Message gefüllt. Den Anfang macht ein String. Dazu wird mittels einer Helper-Klasse CSlotFactoryHelper ein Slot erstellt, welcher den String aufnimmt. Slots sind spezialisierte Klassen für den Transport von Daten und sind immer von einem bestimmten Type (hier CCommonSlotType.STRING). Sie dienen dazu, die Daten platzsparend in ein ByteArray zu überführen, wenn die Daten von NODE zu NODE geschickt werden. Dazu ist natürlich für jeden Datentyp eine eigene Klasse zuständig. Außer den mitgelieferten Slot-Typen lassen sich auch eigene im System registrieren.

Records halten die Slots in einer Map. Der Schlüssel zum Eintrag ist ein SlotKey, der aus einem oder zwei generischen IDs besteht (vom Typ IId). IDs begegnen uns überall, und sie sind recht variabel gehalten. Eine ID kann aus einem Integer, einem String oder einer UUID bestehen. Hier verwenden wir einfach einen Integer ("1") als SlotKey.

Der zweite Slot wird mit einem Integer befüllt (mit einem String "SillySlotKey" als SlotKey), und der dritte Slot mit einem ShortArray und einer UUID ("KEYID003") als SlotKey. Das soll lediglich zeigen, was möglich ist.

Das Herausholen der Daten aus dem Record erfolgt analog. Erst muss der Slot aus der Map geholt werden, wofür wir den SlotKey benötigen. Anschließend holen wir uns den Wert (mit getValue()), welchen wir dann ausgeben. Da getValue() ein Objekt zurück gibt, ist man gezwungen, das Objekt zu casten.

Wie wir sehen, ist es relativ aufwendig, Daten manuell in einen Record zu füllen und diese wieder herauszuholen. Wir benötigen immer jeweils zwei Zeilen Code für ein Datum, und beim Herausholen der Daten sind teilweise Casts notwendig. Dazu benötigt man das Wissen, von welchem Typ die Daten sind, damit richtig gecastet wird. Und schließlich benötigt man auch noch Kenntnis der SlotKeys, um an die Daten zu kommen.

Zum Glück gibt es eine weitere Methode, Messages mit Daten zu verschicken. Das sehen wir im nächsten Beispiel.

Diese Beispiele findest du im Projekt D1ExamplesNode001 im package de.softdevel.d1.examples.node001.example001.