Der Event Admin Service

Veröffentlicht in: Eclipse, Java, RCP | 0

Bei der Entwicklung von Software-Architekturen bekommt die Verwendung von Events und EventHandlern eine immer größere Bedeutung. Betrachtet man CQRS – Axon Framework – oder die CDI Events von JEE 6, so ist hier in letzter Zeit ein klarer Trend zu erkennen.

Umso erstaunlicher, dass das Konzept der Events schon seit Oktober 2005 im OSGI Standart – OSGI Service Compendium – existiert. So wird es vom Event Admin Service ermöglicht, Events zu versenden. Diese werden von EventHandlern, die als OSGI Service registriert seien müssen, behandelt. Da es sich bei dem Event Admin Service um einen OSGI Service handelt, kann dieser z.B. über die ServiceRegistry abgefragt werden:

ServiceReference serviceReference = context.getServiceReference(EventAdmin.class.getName());
EventAdmin eventAdmin = (EventAdmin) context.getService(serviceReference);

Um nun ein Event zu versenden, wird wie bei JMS (Java Message Service) ein Topic definiert, aufgrundlage dessen sich entscheidet, welche EventHandler auf das Event reagieren. Im Vergleich hierzu haben sich die CDI- und CQRS-Events deutlich weiterentwickelt, da es sich bei diesen um POJOs handelt, die bestimmen welche EventHandler zuständig sind. Die CDI-Events können zusätzlich noch Annotations als Qualifier verwendet werden, falls zu einem Event verschiedene Handler existieren, die aber nicht alle ausgeführt werden sollen. Sowohl die CDI- als auch die CQRS-Events beinhalten die Informationen, die vom Handler zur weiteren Verarbeitung benötigt werden. Beim Event Admin Service muss stattdessen ein Dictonary erstellt werden, welches diese Informationen in Form einer Map beinhaltet:

Dictionary eventProperties = new Hashtable();
eventProperties.put(„message“, „Hello World“);
Event event = new Event(„my/topic“, eventProperties);
eventAdmin.sendEvent(event);

Der EventHandler selbst muss das gleichnamige Interface implementieren und als OSGI Service mit dem entsprechenden Topic registriert werden. Hier die recht simple Implementierung des EventHandlers:

public class MyEventHandler implements EventHandler {
@Override
public void handleEvent(Event event) {
// handle the event
}
}

Folgendermassen wird nun der EventHandler als OSGI-Service registriert:

Dictionaryproperties = new Hashtable();
properties.put(EventConstants.EVENT_TOPIC, „my/topic“);
context.registerService(MyEventHandler.class.getName(), new MyEventHandler(), properties);

Um den Event Admin Service verwenden zu können, werden folgende Bundles benötigt:

  • org.eclipse.osgi
  • org.eclipse.osgi.services
  • org.eclipse.equinox.event
  • org.eclipse.equinox.ds

Events sind ein sehr gutes Mittel um Softwarearchitekturen zu entkoppeln. So ist es recht verwunderlich, dass es so lange gedauert hat, bis sich dieses Architektur-Pattern auch in anderen Frameworks wiedergefunden hat.

CDI im Tomcat verwenden

Veröffentlicht in: Java, JEE 6 | 0

Die einfachste Art die Java EE 6 Funktionalität CDI einsetzten zu können, ist die Verwendung eines vollwertigen Application Servers wie z.B. Glassfish in der aktuellen Version 3.1. Um CDI in einem Tomcat 7 verwenden zu können, ist etwas mehr Aufwand vonnöten, da dieser außer der Servlet API 3.0 keine Java EE 6 Komponenten von Haus aus mitliefert.

Um in einer Web-Applikation die innerhalb eines Tomcats läuft CDI bzw. Wend verwenden zu können, reicht ein einziges JAR-Archiv aus: weld-servlet.jar

Dieses kann bequem per Maven in einer Web-Applikation integriert werden:

<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
<version>1.0.1-Final</version>
</dependency>

Zusätzlich wird noch folgender Eintrag in der web.xml des jeweiligen Web-Projektes benötigt:

<listener>
<listener-class>
org.jboss.weld.environment.servlet.Listener
</listener-class>
</listener>

Leider verwendet der Tomcat 6 die Servlet API 2.5, so dass hier nicht so einfach die Vorteile der Servlet API 3.0 zum Einsatz kommen können. CDI selber kann natürlich dennoch verwendet werden, hier kommt es nicht zu Konflikten mit den Libraries des Tomcats.

Quickstart in Java EE 6 und CDI

Veröffentlicht in: Java, JEE 6 | 0

Auf der JAX 2011 konnte ich mir ein paar interessante Vorträge über Java EE 6 im Allgemeinen und CDI im Speziellen anhören. Leider bin ich erst jetzt – einen guten Monat später – dazu gekommen, entsprechende Beispiele zu vertiefen.

Für einen möglichst schnellen Start empfiehlt es sich den Application Server GlassFish in der aktuellen Version 3.1 zu downloaden, bei diesem handelt es sich um die Referenz-Implementierung zu Java EE 6. Dementsprechend liefert GlassFish 3.1 bereits alle Java EE 6 Funktionalitäten inklusive der Servlet API 3.0 und CDI von Haus aus.

Aus Eclipse heraus lässt sich einfach ein Dynamic Web Project erstellen. Eclipse WTP in der aktuellen Version 3.2.3 unterstützt bereits GlassFish 3.1.

Dank der Servlet API 3.0 muss nicht länger die web.xml konfiguriert werden, eine einfache Annotation in der entsprechenden Klasse reicht aus, um das Servlet im Web Container zu registrieren.

@WebServlet(„/MyUserServlet“)
public class MyUserServlet extends HttpServlet {

}

Hier kann nun wie bereits in den Vorgängerversionen gehabt, die doGet Methode überschrieben werden. Anschließend ist das Servlet bereits über den Browser aufrufbar. Für weitere Request-Arten gibt es natürlich ebenfalls Methoden, die überschrieben werden können.

Kommen wir nun zur eigentlichen CDI Funktionalität, welche auch unter dem Namen Weld bekannt ist. Um CDI im Web Container zu aktivieren, ist es notwendig eine Datei beans.xml im WEB-INF Verzeichnis der Web Applikation zu erstellen. Eine leere Datei ist hierfür ausreichend.

Ein Beispiel von CDI ist die fachliche Dependency Injection. Hierbei wird nicht wie in der bisherigen Dependency Injection ein Service injiziert, sondern ein fachlicher Context. In einer herkömmlichen Web Applikation ist es nötig den UserService injiziert zu bekommen, ausschliesslich um an den eingeloggten Benutzer zu kommen. Statt dessen kann man sich nun einfach den Benutzer in die Applikation injizieren lassen und spart sich so den unnötigen Serveraufruf und eine Abhängigkeit auf den UserService.

Hierfür wird lediglich die Annotation @Produces über der Methode getCurrentUser benötigt, anschließend kann CDI eine @Inject Annotation auflösen, mit deren Hilfe der Benutzer an die entsprechende Stelle injiziert werden kann.

Der UserService hierfür sieht so aus:

@Produces
public User getCurrentUser() {
User user = new User(„max mustermann“);
return user;
}

Um den Benutzer in das Servlet injizieren zu lassen, reicht folgendes Code-Fragment:

@Inject User user;

Dieses Verfahren funktioniert allerdings nur, solange nicht weitere Methoden mit @Produces annotiert sind, die einen User zurück geben. Ist dies der Fall müssen diese unterschieden werden. Hierfür werden Qualifier benötigt, die mittels eigener Annotation definiert werden:

@Qualifier
@Retention(RUNTIME)
@Target( { TYPE, METHOD, PARAMETER, FIELD })
public @interface CurrentUser {
@Nonbinding String name();
}

Um das Beispiel interessanter zu machen, wird direkt in der Annotation der Name des Benutzers mit übergeben, so dass an der erzeugenden Stelle, der Name des Benutzers über die Annotation abgefragt werden kann:

@Produces
@CurrentUser(name=““)
public User getCurrentUser(InjectionPoint injectionPoint) {
String username = null;
for (Annotation qualifier : injectionPoint.getQualifiers()) {
if (qualifier instanceof CurrentUser) {
CurrentUser currentUser = (CurrentUser) qualifier;
username = currentUser.name();
}
}
User user = new User(username);
return user;
}

Die Annotation @CurrentUser zeigt an, dass diese Methode lediglich für den CurrentUser zuständig ist. Der Name der hier leer gelassen wurde, spielt keine Rolle, muss aber angegeben werden, da dies in der Annotation so gefordert ist. Der Parameter InjectionPoint wird direkt von CDI in die Methode injiziert. Über diesen Parameter kommt man an die Annotation, die im Injizierungspunkt gesetzt wurde. So kann man den Namen des Benutzers erfragen, der in der Annotation festgelegt wurde und diesen für den zu erstellenden Benutzer verwenden.

Die Stelle an der man den Benutzer injiziert bekommen möchte, sieht so aus:

@Inject @CurrentUser(name=“max mustermann“) User user;

Hier wird der Name gesetzt, der in der @Produces Methode dem Benutzer übergeben wird.

Dies war lediglich ein kleiner Teil der CDI Funktionalität. Ebenfalls sehr interessant ist das Event Konzept, die Möglichkeit einzelne Teile einer Anwendung per Annotation asynchron ausführen zu können, Aspekte unter CDI und vieles mehr.

Doch dazu zu einem späteren Zeitpunkt mehr.