Wicket 6

In den folgenden zwei Abschnitten möchte ich die Nutzung dieser neuen Möglichkeiten in Verbindung mit zwei der prominentesten Frameworks (Spring und JEE 6) vorstellen. In beiden Fällen kann auf die Verwendung der web.xml komplett verzichtet werden.

The Spring Way

Bisher mussten zum Bootstrapping einer Spring-basierten Anwendung entsprechende Listener in der web.xml registriert werden. Seit Spring 3.1 gibt es aber die Möglichkeit, die Initialisierung über eine oder mehrere Implementierungen von WebApplicationInitializer durchzuführen.

Listing 7 zeigt das Starten einer Wicket-Application samt zugehörigem Applikationskontext.

Listing 7
public class WicketApplicationInitializer implements org.springframework.web.WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        XmlWebApplicationContext rootContext = new XmlWebApplicationContext();
        rootContext.setConfigLocation("classpath*:WEB-INF/applicationContext.xml");
        servletContext.addListener(new ContextLoaderListener(rootContext));
        WicketFilter filter = new WicketFilter(new WicketApplication());
        filter.setFilterPath("");
        servletContext.addFilter("wicketFilter", filter).addMappingForUrlPatterns(null, false, "/*");
    }
}

Der Reihe nach werden die gleichen Schritte durchgeführt, die man auch in einer web.xml finden würde:

1.

  1. Erzeugen des Application-Kontexts aus der Datei WEB-INF/applicationContext.xml im Klassenpfad.
    2.
  2. ContextLoaderListener hinzufügen, um den Applikations-Kontext mit dem Servlet-Kontext zusammenzuführen.
    3.
  3. WicketFilter hinzufügen, um die Wicket-Anwendung bereitzustellen

Einziger (gravierender) Haken: Die hier vorgenommenen Einstellungen können nicht durch die web.xml übersteuert werden!

The JEE6 Way

Da das Bootstrapping bei JEE 6 komplett vom Container übernommen wird, ist die Initialisierung einer Wicket-Anwendung entsprechend einfacher (Listing 8).

Listing 8
...
import org.wicketstuff.servlet3.WicketFilter3;
...

@WebFilter(value = "/*", initParams = {@WebInitParam(name = "applicationClassName", value = "com.mycompany.WicketApplication")})
public class CustomFilter extends WicketFilter3 {
}

Man nehme den WicketFilter3 aus Wicketstuff und versehe ihn mit der @WebFilter-Annotation. Diese benötigt den Klassennamen der Wicket-Applikation und den Pfad, für den der Filter ausgelöst werden soll. Das war’s. Als Spring-Verfechter muss ich dann doch zugeben: Das ist schon sehr elegant. Und außerdem gibt es hier keine Einschränkung bei der Verwendung einer web.xml.

CDI

Wicket ist ein sogenanntes Unmanaged-Framework. Die Integration mit App-Servern oder Frameworks findet in optionalen Modulen statt. Bisher hatte man hier die Wahl zwischen Spring, Guice und einer CDI-Integration (Context and Component Injection) durch das Seam-Projekt. Diese wurde allerdings nach Wicket 1.4 nicht mehr weiterentwickelt. Einige Zeit nach dem Release von Wicket 1.5 wurde dann eine semi-offizielle Unterstützung für CDI durch einige Wicket-Kernentwickler bereitgestellt. Diese Integration gestaltete sich deutlich komplizierter als die der anderen Frameworks. Das liegt vor allem an der starken Verzahnung von CDI und JSF (Java Server Faces), der einzigen, in der JEE 6 vorgesehenen Frontendtechnologie.

Tatsächlich wäre die Integration auf Basis der @Inject-Annotation wohl noch recht einfach gewesen. Allerdings würde man hier eine interessante Neuerung nicht nutzen können. Die Rede ist von Conversations. Klassischerweise hat man bei Webanwendungen die Wahl zwischen drei an Anwendungsereignisse gebundenen Objekt-Scopes:

  • Objekte im Request-Scope existieren während des Requests.
  • Objekte im Session-Scope existieren für die Lebensdauer der Session.
  • Objekte im Application-Scope existieren für die gesamte Laufzeit der Anwendung.

Über die Jahre hat sich gezeigt, dass diese bei Weitem nicht alle Fälle abdecken können. Insbesondere bei Wizardfunktionalität wäre ein Scope notwendig, der zwischen Request und Session angesiedelt ist und dessen Lebensdauer vom Entwickler beeinflusst werden kann. Dieser auf eine Konversation festgelegte Scope wurde in der bei JEE 6 verwendeten Form vom Seam-Projekt konzipiert. Mit ihm lassen sich z. B. Backingobjekte oder der EntityManager für einen bestimmten Ablauf hinterlegen. Leider ist er außerhalb von JSF nicht über die Standard-APIs verwendbar. Für eine vollständige Integration musste man also den Standard verlassen und auf Implementierungsspezifika des Containers zurückgreifen. Schön ist anders.

Da die beiden prominentesten Open-Source-JEE-6-Server (Glassfish und JBoss 7) auf Weld als CDI-implementierung setzen, war es eine logische Konsequenz, diese als Basis für das Wicket-CDI-Projekt zu verwenden. Für jede weitere Variante (OpenWebBeans, CanDI, …) müsste auch eine entsprechende Integration implementiert werden.

Zumindest wird zwar die bekannteste Variante unterstützt, aber selbst hier gibt es noch einen weiteren Haken: JBoss stellt nicht alle notwendigen Bibliotheken (um genau zu sein: seam-conversation-weld) in Maven Central bereit, weshalb auch Wicket-CDI dort nicht veröffentlicht werden kann. Autsch! Um es dennoch nutzen zu können, gibt es eine umfassende Anleitung im 42-Lines Github-Repository [2].

Ich hatte bisher schon reichlich Gelegenheit, damit zu arbeiten und würde dieses Modul jederzeit auch in eigenen Projekten einsetzen. Wer also einen Weld-basierten JEE-6-Container nutzt und dort Wicket als Frontend-Layer verwenden möchte, bekommt hier alles, was notwendig ist.

Es bleibt zu hoffen, dass sich JBoss erweichen lässt, diese Abhängigkeiten in Maven-Central zu veröffentlichen oder die (an diesem Punkt) mangelhafte CDI-Spezifikation anzupassen.


Themen der letzten Seite:

  • Experimentelles
  • WebSockets
  • Zusammenfassung
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.