Schlagwort-Archive: Wicket

Vergleich von JVM-Web-Frameworks

Der Vergleich von Web-Frameworks ist eine unendliche Geschichte. Eben habe ich mich schmerzlich von JSF abgewandt und Apache Wicket zugewendet. Das Urgestein Matt Raible hat dazu auf Spring I/O 2012 einen guten Vortrag gehalten:

http://de.slideshare.net/mraible/comparing-jvm-web-frameworks-spring-io-2012

Seine Sicht ist zwar subjektiv, wie immer, aber er hat zu dem Thema wirklich sehr viele Argumente und viel zu sagen.

Customize Wicket StringResource Loading for Entity classes

Problemstellung

Apache Wicket besitzt einen ausgefeilten Mechanismus zum Laden für Stringresourcen zur Internationalisierung (i18n) einer Anwendung. Dieser ist Komponenten-orientiert und findet Resourcen im Teilast der Komponentenhierarchie, den wicket-package.properties, der Superklassenhierarchie, und an globalen Orten für die Anwendung.

In einer Anwendung ist es aber durchaus sinnvoll, die Resourcen den Datenbank-Klassen (Entities) zuzuordnen, eine Property-Datei für jede Klasse, in der zum Beispiel Label, Titel und Description für ein Datenbankfeld stehen. Diese Resource-Dateien bleiben im Loading-Mechanismus von Wicket aber außen vor.

Da Wicket aber für die Erweiterung des Loading Möglichkeiten vorgesehen hat, ist dies keine Einschränkung, man muss nur wissen wie. Hierzu im Folgenden meine Erkenntnisse zur Implementierung eines eigenen ResourceLoaders, angeregt durch eine Seite im Wiki.

Lösungsansatz

Schon in zwei früheren Posts habe ich eine Version gepostet, die jedoch das Caching der Resourcen durch Wicket nicht berücksichtigte und daher fehlerhaft war. Statt dieser zwei Postings hier also heute die verbesserte Version.

Weiterlesen

Wicket in meinem MoinMoin Wiki

In einem ersten Artikel zu meinem Wiki hab ich dessen Notwendigkeit und Verwendung geschildert. Hier nun ein Beispiel in Form der Seite für Apache Wicket, das Java Web Framework, in das ich mich gerade einarbeite, was in der Anfangsphase immer auf eine Sammlung guter Links auf Tutorials, HowTos und Artikel heraus läuft. Diese möchte ich hier teilen. Da mein Wiki nicht öffentlich ist, und ich spontan nicht genau weiß, wie ich die Seite hier einbinden soll, versuche ich mal das HTML einfach ein zuschleußen. Bitte dabei die schlechte Formatierung verzeihen. Deswegen auch noch als ApacheWicket Seite PDF Anhang.

Weiterlesen

Mein MoinMoin Wiki

Früher habe ich geglaubt, ich könnte mir alle Zwischenergebnisse und Erkenntnisse, interessante Links, HowTos und gute Blog-Artikel für meine Arbeit merken. Stimmt aber nicht, liegt auch nicht am Alter, die Annahme war schon damals falsch.

Mein Lösungsansatz für diese Notizen war natürlich nicht der Zettelkasten, sondern liegt im Web, in einem Wiki. Dies hat viele Vorteile:

  • Überall dabei, wo man Netz hat, auch beim Kunden und auch dort nicht nur zur Recherche, sondern gleich editierbar.
  • Auf allen Maschinen synchron, da zentrale Datenhaltung auf dem Server
  • Flache Struktur wie bei einem Wiki üblich. Nachdem sich wenige Konventionen und Kategorien herausgebildet haben, kann man einfach hinzufügen, ohne ständig Hierarchien und Inhaltsverzeichnisse umzustellen.
  • Vielleicht am wichtigsten: Volltextsuche. Man findet mühelos  Informationen, deren Speicherort man nicht mehr erinnert.
  • Ideal auf für Bilder, Links und Anhänge. Vieles steht schon woanders im Web und ist prima zu verlinken. Das geht auf Papier nicht. Einen Artikel als PDF beiheften, auch nicht.
  • Genügend syntaktische Möglichkeiten, auch zur Hervorhebung von Programmcode und Kommandos.

Aus einem Nebenprojekt ist so über die Zeit ein unverzichtbar wertvolles Arbeitsmittel gewachsen, ohne dass es gar nicht ginge. Es enthält bereits 345 eigene Seiten! Ich muss mich aber zwingen, auch dort immer nachzuschlagen, denn oft glaube ich gar nicht was ich zu einem früheren Zeitpunkt schon wertvolles hinterlegt habe.

Relativ bald habe ich dem Arbeits-Wiki ein zweites privates zur Seite gestellt, in dem zum Beispiel Urlaubs-Tipps, Kochrezepte und Betriebsanleitungen und Kaufbelege für gekauftes Inventar landen. Nicht so lebendig, aber auch gut.

MoinMoin logo

Die meisten nehmen für Ihr eigenes Wiki als Softwarebasis immer MediaWiki, da sie es von Wikipedia her kennen und für das beste halten. Es ist auch sicherlich sehr ausgefeilt, aber eben für Wikipedia geschaffen. Für das eigene Wiki gibt es bessere Lösungen. Ich habe mich damals für MoinMoin entschieden, und diese Entscheidung eigentlich nicht bereut. Es ist zuverlässig, weit verbreitet und tut das was es soll.

Eine Beispielseite gibt es im folgenden Artikel.

EJB in Wicket: Wrapping in ein LoadableDetachableModel

Das Problem

Im Artikel „Wicket, JPA und CMT“ habe ich meine Nöte mit Wicket-Pages geschildert, da sich dort prinzipbedingt keine EJB als member halten lassen, ohne bei der Serialisierung einen Fehler zu liefern. Auch in einem Beitrag der mailing list habe das Thema vertieft und was gelernt.

Die Lösung

Ansatz

Letztendlich bin ich aber auch auf eine eigene, ganz gute Lösung gekommen, die ich hier vorstellen möchte. Die Idee ist, das EJB vor dem Request zu holen und nach dem Request, noch vor der Serializierung, zu entfernen, wie das in Wicket’s LoadableDetachableModel sehr gut gemacht wird. Also der klassische Wicket-Ansatz große Datenblöcke nicht mit der Seite wegzuspeichern, sondern vor Gebrauch dynamisch wieder zu laden. Das Laden des EJB geschieht konsequenter Weise nicht mit dependency injection, sondern mit einem JNDI-Lookup.

Code

Die Implementierung des Model sieht so aus:

/**
 * Model for JPA facade beans.
 * @author Dieter Tremel
 */
public class EntityFacadeModel extends LoadableDetachableModel {

    private Class entityClass;

    public EntityFacadeModel(Class entityClass) {
        this.entityClass = entityClass;
    }

    @Override
    protected AbstractFacade load() {
        AbstractFacade result = null;
        try {
            InitialContext ctx = new InitialContext();
            result = (AbstractFacade) ctx.lookup("java:module/" + entityClass.getSimpleName() + "Facade");
        } catch (NamingException ex) {
            Logger.getLogger(EntityFacadeModel.class.getName()).log(Level.SEVERE, null, ex);
        }
        return result;
    }
}

In der Seite wird das so eingebaut:

    EntityDataProvider buchProvider = new EntityDataProvider<>(new EntityFacadeModel(Buch.class));
    DefaultDataTable dTable = new DefaultDataTable<>("datatable", columns, buchProvider, 10);

Im ebenfalls generischen EntityDataProvider muss dann die detach()Methode überschrieben werden:

    @Override
    public void detach() {
        facadeModel.detach();
        super.detach();
    }

Verfeinerung

Models, die eine EJB kapseln, kann man auch generisch implementieren, es muss dann nur noch die Bildung des Namens für den Lookup implementiert werden.

/**
 * Abstract model for wrapping an Enterprise Java Bean (EJB) in a {@link LoadableDetachableModel}.
 * The model can detach the EJB before serialization, which would fail, since EJB are not serializable.
 * On atach the EJB is loaded by an JNDI lookup.
 * The name of the lookup must be returned by {@link #getEjbName() }.
 * The input data for {@link #getEjbName() } are given in a constructor, which an implementation has to define.
 *
 * @param  Type of wrapped EJB.
 * @author Dieter Tremel
 */
public abstract class AbstractEjbModel extends LoadableDetachableModel {

    /**
     * Get the name of the EJB type suitable for lookup.
     * @return EJB name.
     */
    protected abstract String getEjbName();

    @Override
    protected EJB load() {
        EJB result = null;
        try {
            InitialContext ctx = new InitialContext();
            result = (EJB) ctx.lookup("java:module/" + getEjbName());
        } catch (NamingException ex) {
            Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error at JNDI lookup for " + getEjbName(), ex);
        }
        return result;
    }
}

EntityFacadeModel wird dann deutlich übersichtlicher:

/**
 * Model for JPA facade beans.
 * @param  Type of JPA Entity.
 *
 * @author Dieter Tremel
 */
public class EntityFacadeModel extends AbstractEjbModel<AbstractFacade> {

    private Class entityClass;

    /**
     * Constructor creating an new model for a facade of an entity class.
     * @param entityClass Class of entity.
     */
    public EntityFacadeModel(Class entityClass) {
        this.entityClass = entityClass;
    }

    @Override
    protected String getEjbName() {
        return entityClass.getSimpleName() + "Facade";
    }
}

Mit dieser Lösung kann man doch gut leben, insbesondere, wenn der JNDI-Lookup performant ist, was ich doch sehr hoffe.