Standardaufgaben wie Zoomen, Rotieren oder das Aktivieren von AddOns sind innerhalb der jadice Pakete in jeweils eigenständige Kommandos gekapselt, die von Aktionen aufgerufen werden können und die die eigentliche Ausführung der gewünschten Funktionalität übernehmen. Typische Kommandos benötigen zu ihrer Ausführung eine Anzahl von Objekten, die ihnen über den weiter oben beschriebenen Context zur Verfügung gestellt werden. Damit ein Kommando erfolgreich ausgeführt werden kann, müssen alle von ihm benötigten Objekte im Kontext vorhanden sein. Es ist Aufgabe des Integrators, dies sicherzustellen.

Alle Kommandos sind Instanzen der Klasse InjectedCommand. Zur Ausführung benötigte Objekte werden InjectedCommands via Dependeny Injection vollautomatisch und typsicher zur Verfügung gestellt. Es existieren zwei Arten der Injektion. Zum einen können Konfigurationswerte und zum anderen können Kontextobjekte dynamisch bereitgestellt werden. Beide Arten von Dependency Injection werden im Quellcode durch Aufbringen von Java-Annotationen ermöglicht und im Folgenden vorgestellt.

Die Parameter-Injection bezieht sich auf Konfigurationswerte, die aus den commands.properties stammen. Um einen Parameterwert zur Verfügung zu stellen, sind folgende Schritte notwendig:

  1. Definition einer Klassenvariablen in der Command-Implementation. Das Framework nimmt selbstständig eine gegebenenfalls notwendige Typ-Konvertierung (beispielsweise für int-Werte) vor.

  2. Erzeugen von public getter/setter Methoden für die Klassenvariable und Aufbringen der Annotation Parameter am Setter.

  3. Eintragen des neuen Parameters in der commands.properties Datei. Die Einträge müssen dem folgenden Schema entsprechen:

    <command-name>.param.<parameter-name>=<parameter-value>

    Der zu verwendende Parametername entspricht dem Methodennamen des setters aber ohne das set-Prefix und mit dem ersten Buchstaben klein geschrieben.

Für Parameter, die auf diese Weise angefordert werden, stellt das Framework sicher, dass diese nach Instanziierung der Klasse bereitstehen.

Für Fälle, in denen der Parametername in commands.properties nicht aus dem Methodennamen generiert werden soll, besteht die Möglichkeit, die Annotation @Parameter mit einem optionalen Argument name zu versehen, das den in der Properties-Datei verwendeten Namen definiert. Des Weiteren existiert ein Annotations-Argument optional, mit dem definiert werden kann, dass das Fehlen der Parameter-Definition in commands.properties nicht zu einem Fehler führen soll. Das Kommando wird dann trotzdem instanziiert und annotierte Felder behalten ihren in der Klasse definierten Default-Wert.

Die Parameter-Injection funktioniert für folgende Datentypen: String, Color, enums und die primitiven Datentypen.

Die zweite Möglichkeit ist die Argument-Injection. Während Parameter aus den Properties stammen, beziehen sich Argumente auf im Context vorhandene Objekte und werden aus diesem heraus zur Verfügung gestellt.

Das Anfordern von Objekten aus dem Kontext geschieht (analog zur Parameter-Injektion) durch Anbringen der Java-Annotation Argument an einer setter Methode. Das Framework führt einen Aufruf der Methode mit dem ersten im Kontext gefundenen Objekt des entsprechenden Typs durch. Dies geschieht vor einem später eventuell erfolgenden Aufruf der execute()-Methode.

In realen Szenarien kann es leicht vorkommen, dass der Kontext mehrere Objekte desselben Typs enthält. Anstatt einfach das erste Objekt des gewünschten Typs anzufordern, besteht alternativ dazu die Möglichkeit, sämtliche Objekte eines Typs abzufragen. In diesem Fall werden alle gefundenen Objekte in einer Collection des entsprechenden Typs zurückgegeben. So werden beispielsweise mit dem Code-Fragment

@Argument
public void setSomeStrings(Collection<String> allContextStrings){…};

sämtliche String-Instanzen aus dem Kontext angefordert und injiziert.

In Zusammenhang mit Collections existiert eine Einschränkung der InjectedCommands: Es ist nicht möglich, Objekte des Typs Collection im Kontext abzulegen und mittels Argument-Injection auszulesen. Grund hierfür ist die Generic Type Erasure: Zur Laufzeit sind die durch Generics spezifizierten Typinformationen nicht vorhanden, sodass eine korrekte Typkonvertierung nicht zuverlässig möglich ist. Soll eine Ansammlung von Objekten im Kontext abgelegt und injiziert werden, so empfehlen wir dafür ein dediziertes Fachobjekt zu erstellen, das die Objektmenge vorhält.

Die Annotation @Argument bietet verschiedene Optionen an, die den Injektions-Vorgang beeinflussen können. Wie es schon für Parameter der Fall war, können auch Argumente als optional markiert werden. Des Weiteren existiert eine Option boolean allowOtherMatches, die festlegt, ob bei der Abfrage nach einem einzelnen Objekt das Vorhandensein mehrerer gleicher Objekttypen zu einem Fehler führen soll. Die Option boolean matchSubclasses legt fest, ob bei der Suche nach Objekten im Kontext auch Subtypen des angeforderten Typs zurückgeliefert werden sollen. Eine letzte Option, Class<? extends Object> match, definiert nach welchem Objekttyp der Kontext durchsucht werden soll. Wie aus dem Beispiel bereits hervorging, wird der gewünschte Typ im Regelfall automatisch erkannt. Dieses zusätzliche Attribut erlaubt es jedoch, eine nähere Einschränkung – zum Beispiel auf eine bestimmte Subklasse – zu treffen.

Eine letzte Möglichkeit der Argument-Injizierung bietet die Annotation @AllArguments. Diese stellt sämtliche Argumente des Kontextes zur Verfügung. Im Regelfall geschieht dies über einen Rückgabewert des Typs Collection<Object>, wobei zu bedenken ist, dass die Klasse Context das Interface Collection implementiert. Man bekommt daher eigentlich eine Instanz von Context zurück. Um an dieser Stelle keine manuellen Typ-Checks und -Konvertierungen durchführen zu müssen, kann auf der Annotation @AllArguments die Option match = Context.class spezifiziert werden. Ist diese Option vorhanden, so wird direkt eine Instanz von Context zurückgegeben.

[jadice document platform Version 5.4.2.13: Dokumentation für Entwickler. Veröffentlicht: 2020-04-08]
loading table of contents...