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:

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

Die Annotation @Parameter kann an jeder Klassenvariablen angebracht werden, unabhängig von deren Sichtbarkeits-Modifier. Zu beachten ist jedoch an dieser Stelle, dass in manchen Security-Kontexten (zum Beispiel innerhalb von Applets) nur public möglich ist, da der Aufruf von Field.setAccessible(true) in einer SecurityException resultiert.

Es besteht weiterhin auch die Möglichkeit, die Annotation @Parameter an einer setter-Methode anzubringen. Der erwartete Parametername entspricht dann dem Methodennamen ohne das set-Prefix und mit dem ersten Buchstaben klein geschrieben. Bezüglich der Methodensichtbarkeit gelten die gleichen Regeln wie für Klassenvariablen.

Für Fälle, in denen der Parametername in commands.properties nicht dem Variablennamen entsprechen oder 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 Basis-Datentypen (wie int, float oder boolean).

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 Objekte aus dem Kontext geschieht (analog zur Parameter-Injektion) durch Anbringen der Java-Annotation Argument an einer Klassenvariablen. Das Framework befüllt daraufhin automatisch diese Variable mit dem ersten im Kontext gefundenen Objekt des entsprechenden Typs. Es wird garantiert, dass die Variable befüllt ist wenn ein Aufruf der execute()-Methode erfolgt.

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
private Collection<String> someStringArgument;

sämtliche String-Instanzen aus dem Kontext angefordert und in das Feld 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.

Wie auch schon bei den Parametern der Fall, ist es auch für Annotationen des Typs @Argument möglich, statt einer Klassenvariable die entsprechende setter-Methode zu annotieren. Auch bezüglich der Java Sichtbarkeits-Schlüsselworte gilt oben gesagtes.

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 5 Dokumentation. Erstellungsdatum: 2012-01-19]
loading table of contents...