Wicket: A slightly better “Open Session in View”

We recently participated at the The Plat_forms contest (more on that in a few days). Coding a full application in less than 30 hours is quite the task and there’s no room for wasting time.

Sadly, we wasted time. A lot. On the persistence layer.

Wasted may be too hard of a word but we spent too much time building the actual business services needed to populate the view layer.

You might wonder why it took so much time.

Well, because each use case needs a different service method which provides an entity and all it’s relations initialized as deep as the view layer will use it.

Now you might give me a confused look and ask “Why the hell did you bother building those and didn’t use Open Session in View?” and I would have answered with tirade on why I consider it an anti pattern.

But sometimes you have to rethink opinions you held dear for a long time.

Sometimes verbose is better

Before I continue to dive into Open Session in View (OSiV) a little deeper, let’s take a look why I still prefer the verbose approach. Building a relational persistence layer using an ORM can be a tricky thing.

There’s a lot of things that can go wrong. Especially if JOINs are involved. Any access to a collection or a referenced entity can cause havoc on your application performance.

By avoiding Open Session in View this problem is easily avoided as the developer has to think about every single JOIN as he will have to build the queries to resolve them.

There will also be integration tests covering individual queries and the possibility to do load tests based on those.

The moment you start using OSiV all these advantages disappear.

Sometimes terse is better

A contest (or building a prototype) has different rules. The only thing that counts is “getting it done”.

That’s where the verbose approach starts to fail as it demands a lot of code being written and tested.

Enter Open Session in View

Open Session in View

Using OSiV the database session is opened and closed through a Servlet Filter.

As the session stays open in the view layer you are free to navigate the entity-tree as you please.

This convenience comes at a price and, asides the problems I already mentioned, there are two key disadvantages:

N+1 Select problem

The most dreaded problem is the N+1-Select-Problem. Accessing collections without appropriate annotations will cause the ORM to do a Select for each entry in the collection.

So you will get 1 initial select plus N (=size of collection) subsequent selects. Using todays query-statistics-tools (every good ORM has a set of these) they are easy to find if they occur.

They are easily introduced and hard to find during development. With a good project setup they should be discovered during load testing.

If you are actually doing load tests …

Exception in the filter

ORMs do a lot of things when a database session is closed. Doing a lot of things also means that a lot of things can go wrong.

With OSiV the session is closed after the web request has been processed by the web framework. There is no way you can react on these exceptions in a meaningful way without putting significant logic into the ServletFilter. Not really a good idea.

Wicket

There is no way solving N+1 in a generic way. But the exception problem is easily solved. Well, if Wicket is your view layer. Wicket provides hooks to every step of request processing through

IRequestCycleListener. The following OpenSessionInRequestCycleListener shows how to build a Hibernate based OSiV for Wicket.

import org.apache.wicket.MetaDataKey;

import org.apache.wicket.request.IRequestHandler;

import org.apache.wicket.request.cycle.AbstractRequestCycleListener;

import org.apache.wicket.request.cycle.RequestCycle;

import org.hibernate.FlushMode;

import org.hibernate.HibernateException;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Configurable;

import org.springframework.dao.DataAccessResourceFailureException;

import org.springframework.orm.hibernate4.SessionFactoryUtils;

import org.springframework.orm.jpa.EntityManagerFactoryUtils;

import org.springframework.orm.jpa.EntityManagerHolder;

import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.persistence.EntityManager;

import javax.persistence.EntityManagerFactory;

import javax.persistence.PersistenceException;

import javax.persistence.PersistenceUnit;

@Configurable

public final class OpenEntityManagerInRequestCycleListener extends

        AbstractRequestCycleListener {

    private static final Logger LOG = LoggerFactory.getLogger(OpenEntityManagerInRequestCycleListener.class);

    @SuppressWarnings("serial")

    static final MetaDataKey<Boolean> PARTICIPATE = new MetaDataKey<Boolean>() {};

    @PersistenceUnit

    private EntityManagerFactory emf;

    @Override

    public void onBeginRequest(RequestCycle cycle) {

        cycle.setMetaData(PARTICIPATE, TransactionSynchronizationManager.hasResource(emf));

        if(!cycle.getMetaData(PARTICIPATE)) {

            try {

                LOG.debug("OPENING NEW ENTITY MANAGER FOR THIS REQUEST.");

                EntityManager em = emf.createEntityManager();

                TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));

            }

            catch (PersistenceException ex) {

                throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);

            }

        }       

    }

    @Override

    public void onRequestHandlerExecuted(RequestCycle cycle, IRequestHandler handler) {

        if (!cycle.getMetaData(PARTICIPATE)) {

            try {

                LOG.debug("CLOSING ENTITY MANAGER FOR THIS REQUEST.");

                EntityManagerHolder emHolder = (EntityManagerHolder)

                        TransactionSynchronizationManager.unbindResource(emf);

                EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());

            }

            catch (WhateverExceptionYouAreInterstedIn e) {

                //DOSTUFF

            }

        }

    }

    @Override

    public IRequestHandler onException(RequestCycle cycle, Exception ex) {

        return super.onException(cycle, ex);    //To change body of overridden methods use File | Settings | File Templates.

    }

    protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {

        try {

            Session session = SessionFactoryUtils.openSession(sessionFactory);

            session.setFlushMode(FlushMode.MANUAL);

            return session;

        }

        catch (HibernateException ex) {

            throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);

        }

    }

}

And the same using JPA2:

import org.apache.wicket.MetaDataKey;

import org.apache.wicket.request.IRequestHandler;

import org.apache.wicket.request.cycle.AbstractRequestCycleListener;

import org.apache.wicket.request.cycle.RequestCycle;

import org.hibernate.FlushMode;

import org.hibernate.HibernateException;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Configurable;

import org.springframework.dao.DataAccessResourceFailureException;

import org.springframework.orm.hibernate4.SessionFactoryUtils;

import org.springframework.orm.hibernate4.SessionHolder;

import org.springframework.transaction.support.TransactionSynchronizationManager;

@Configurable

final class OpenSessionInRequestCycleListener extends

        AbstractRequestCycleListener {

    @SuppressWarnings("serial")

    static final MetaDataKey<Boolean> PARTICIPATE = new MetaDataKey<Boolean>() {};

    @Autowired

    private SessionFactory sessionFactory;

    @Override

    public void onBeginRequest(RequestCycle cycle) {

        cycle.setMetaData(PARTICIPATE, TransactionSynchronizationManager.hasResource(sessionFactory));

        if(!cycle.getMetaData(PARTICIPATE)) {

            Session session = openSession(sessionFactory);

            TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));

        }       

    }

    @Override

    public void onRequestHandlerExecuted(RequestCycle cycle, IRequestHandler handler) {

        if (!cycle.getMetaData(PARTICIPATE)) {

            try {

                SessionHolder sessionHolder =

                        (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);

                SessionFactoryUtils.closeSession(sessionHolder.getSession());

            }

            catch (WhateverExceptionYouAreInterstedIn e) {

                //DOSTUFF

            }

        }

    }

    protected Session openSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {

        try {

            Session session = SessionFactoryUtils.openSession(sessionFactory);

            session.setFlushMode(FlushMode.MANUAL);

            return session;

        }

        catch (HibernateException ex) {

            throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);

        }

    }

}

Both use the same mechanism. Overwrite onRequestHandlerExecuted and go wild. Throw a RestartResponseException or recover gracefully, it’s up to you.

End

There’s only one question left: Would I use it?

Well, to be honest: It depends.

If I ever had to do something like Plat_forms again or a project prototype I would definitely go for it.

For a mission critical application I still prefer to go the save route and know each JOIN by its first name.

Advertisements

Back on the Blog, again

As you might have noticed: It’s been pretty quiet around my blog.

I took an offer to write a book about my favorite web framework, Apache Wicket.

Together with a bunch of articles I did for both it-republik (Wicket 1.5 Wicket 6 and the German Java Magazin_ (1, 2, 3, 4) I basically spent all my time writing about and coding Wicket. A few weeks ago I finally hit the last milestone of this year by attending the Plat_forms-Contest in Berlin, an experience I am going to write about soon.

Let’s keep it short:

  • I am again back on the blog.
  • I got a ton of notes I need to turn into posts.

Time to get going.

P.S.: I will do a few more articles in German. Looks like there is no good way to provide an article in two different languages on wordpress. This might lead to a few more changes to this blog.

Wicket und CSRF (deutsch)

Nach einer Diskussion die ich vor Kurzem zum Thema CSRF (Cross Site Request Forgery) hatte möchte ich kurz auf die Möglichkeiten zum Umgang mit diesem Angriff in Wicket eingehen. Tatsächlich handelt es sich hier um einen oft unterschätzten Angriffsvektor der eine Schwäche des Browsers und nicht der eigentlichen Webanwendung ausnutzt.

Der Angriff

Der Ablauf eines CSRF-Angriffs ist schnell erklärt.

  1. Ein Benutzer authentifiziert sich in einer Webanwendung
  2. Eine entsprechende Sitzung wird eröffnet und der Browser erhält ein Cookie
  3. Der Benutzer navigiert, ohne sich abzumelden, auf eine andere Seite (oder öffnet ein weiteres Tab/Browser-Window).
  4. Auf dieser Seite hat unser Angreifer ein entsprechendes JavaScript oder eine verstecktes Frame eingebaut mit dessen Hilfe der Browser dazu veranlasst wird eine URL innerhalb der anderen Webanwendung zu öffnen.
  5. Da das Cookie immer noch gültig ist wird dies automatisch mitgeschickt und der Angreifer hat Zugriff.

Natürlich versuchen Browserhersteller Möglichkeiten für diesen Angriff zu minimieren.

Grundsätzlich sollte man als Webentwickler aber davon ausgehen, dass diese Mechanismen nicht funktionieren.

So manchem (Jemand fühlt sich gleich angesprochen 😉 ) zuerst die Möglichkeit via AJAX und XmlHTTPRequest in den Sinn. Allerdings gibt es hier eine wichtige Beschränkung die meines Wissens in allen Browsern korrekt umgesetzt ist. Ein XmlHTTPRequest kann nur auf den Ursprungsserver abgesetzt werden. Somit sind extern nachgeladene Skripten außen vor. Hat man natürlich eine Cross-Site-Scripting-Schwäche in der Anwendung …

Die Verteidigung

Grundsätzlich ist Wicket, wie jedes andere Webframework, anfällig für diese Angriffe. Allerdings liefert es auch alles was benötigt wird um diesen Angriff deutlich zu erschweren oder ihn sogar unmöglich zu machen.

In Wicket 1.4 gibt es hierfür die CryptedUrlWebRequestCodingStrategy. Mit folgendem Code-Snipplet kann sie in der Application registriert werden.

...
    protected IRequestCycleProcessor newRequestCycleProcessor() {
        return new WebRequestCycleProcessor() {
        protected IRequestCodingStrategy newRequestCodingStrategy() {
        return new CryptedUrlWebRequestCodingStrategy(new WebRequestCodingStrategy());
    }
...
}

Wicket 1.5 bietet die gleiche Funktionalität im CryptoMapper. Der wie folgt registriert wird:

...
    @Override
    public void init() {
        super.init();
        setRootRequestMapper(new CryptoMapper(getRootRequestMapper(), this));
    }
...

In beiden Fällen wird von un an für jede neu erzeugte Session ein entsprechender Schlüssel erzeugt und in ihr hinterlegt. Im Folgenden wird jede URL, bevor sie ausgeliefert wird, mit diesem verschlüsselt.

Beim Aufruf einer URL in der Anwendung (via AJAX oder dem Klicken eines Links) versucht Wicket diese zu entschlüsseln. Funktioniert dies nicht, was auf alle URLs zutrifft die nicht von Wicket ausgeliefert wurden, wird eine Fehlermeldung erzeugt.

Nachteile

Alles hat seinen Preis, auch der Schutz vor CSRF-Angriffen. Man verliert die Möglichkeit BookmarkablePages zu nutzen. Auch ihre URLs werden entsprechend verschlüsselt. Da der Schlüssel für jede Session neu erzeugt wird sind diese Links spätestens nach dem Ausloggen ungültig.

Durch die Nutzung von PageMounts kann man dieses Problem abmildern da deren URLs immer verfügbar sind.

Auch mag es stören eine Schlüssel pro Session zu erzeugen da dies die Existenz einer Session voraussetzt. Via Application.getSecuritySettings().setCryptFactory() lässt sich hier ein eigenes CryptFactory registrieren welches einen applikationsweiten Schlüssel erzeugt.

Fazit

Trotz der erwähnten Nachteile sehe ich die CryptedUrlWebRequestCodingStrategy als das sicherste und bequemste Mittel zur Abwehr von CSRF-Angriffen. Wer sich Sorgen um die zusätzliche Last durch die Verschlüsselung macht wird hier demnächst noch eine kleine Lastanalyse finden.

Wicket Wizards (deutsch)

Wizards sind ein wichtiger Bestandteil eines jeden GUI-Frameworks.
Natürlich bietet auch Wicket entsprechende Komponenten.
Basis jedes Wizards ist die abstrakte Klasse Wizard.
Diese bringt eine entsprechende ButtonBar mit Buttons um zwischen den Einzelschritten zu navigieren und zum Bestätigen/Abbrechen.
Wer eigen Navigationsoptionen einbauen will kann Wizard.newButtonBar(String) überschreiben.
Für das Beispiel verwende ich allerdings die mitgelieferte Variante.
Der zweite Baustein ist das WizardModel.
Dieses bildet den zentralen Dreh-und ANgelpunkt für alle Wizard-Funktionen.
Es kennt alle Schritte, ihre Reihenfolge und den aktuell ausgewählten.
Fehlen nurnoch die einzelnen Schritte. Diese werden als WizardSteps implementiert und sind einfache Panels die vom Wizard gegeinander ausgetauscht werden.
Somit wird ein Wizard wie folgt erzeugt.

public class UserWizardPanel extends Wizard {
 public UserWizardPanel(String id) {
 super(id);
 setDefaultModel(new CompoundPropertyModel<User>(new User()));
 WizardModel wizardModel = new WizardModel();
 wizardModel.add(new UserCredentialsPanel(Model.of("User Credentials"), Model.of("Please give your credentials.")));
 wizardModel.add(new UserDetailsPanel(Model.of("User Credentials"), Model.of("Please give your credentials.")));
 wizardModel.add(new UserMessageToTheWorldPanel(Model.of("User Credentials"), Model.of("Please give your credentials.")));
 init(wizardModel);
 }

@Override
 protected Component newButtonBar(String id) {
 return super.newButtonBar(id);
 }

@Override
 public void onFinish() {
 System.out.println("DONE!!");
 }

@Override
 public void onCancel() {
 System.out.println("CANCEL!!");
 }
}

NoScript

Der Wizard verwendet AJAX um zwischen den Schritten hin- und herzuspringen. Im NoScript-Fall werden hieraus, wie üblich, Page-Requests wodurch Wizards auch ohne JavaScript funktionieren.

Das ganze Beispiel gibt’s hier als Quickstart.

2011 is over

A little late but my official end of 2011 was last week.

With the relase of my book on wicket and giving two talks at bedcon I finally finished the last of my new years resolutions.

Time to get going on the plans for this year.

  • There’s gonna be a (German) series of blog-posts on Wicket-related issues to supplement my book.
  • I finally got started with Scala and I am starting to work through “The Art of Software Development” by Knuth.
  • More JEE6: Since preparing the Wicket-JEE6-Talk for Bed-Con I am completely convinced that I have to become a JEE6-god. Let’s see how that goes;)

Uh, and last but not least:

  • Finally see Meshuggah live for te second time.

Article about Wicket 1.5 at JAXenter (German)

An article I did on Wicket 1.5 just gut published on the German JAXenter.

Tomcat 7 with full JTA

Everytime I clean my home directory I purge something important.

Just like a week week ago when I  realized my Tomcat 7 installation was gone and with it all the things I had to do to get JOTM running in there.

Once again I spent a while to get everything back together.
But THIS time I am writing it down.

Tomcat Setup

So I want to have Tomcat 7 with full JTA (should also work on older Tomcat versions).
I will be using JOTM as it provides everything I need.

After downloading the JOTM-distribution copy the following jars to <tomcat-home>/lib.

  • commons-logging-api.jar
  • jotm-core.jar
  • log4j.jar
  • ow2-connector-1.5-spec.jar
  • ow2-jta-1.1-spec.jar
I will also add the tomcat connection pool to show a full example later on.
Download the distribution and add the following jars to <tomcat-home>/lib.
  • tomcat-jdbc.jar
  • tomcat-juli.jar

JNDI

Now we need to tell Tomcat how to create the required JNDI-resources.

Note:
Everything created using the Resource-tag will end up in java:comp/env/. Tomcat doesn’t provide functionality to put it somewhere else (or I was simply too blind to find it).

To make resources available we need to edit <tomcat-home>/conf/context.xml.
The first thing we need to add is a connection pool to showcase the useage of JTA later on.

<ResourceLink global="jdbc/myDB" name="jdbc/myDB" type="javax.sql.DataSource"/>
<Resource
	driverClassName="org.h2.Driver"
	factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
	name="jdbc/myDB"
	password=""
	type="javax.sql.DataSource"
	url="jdbc:h2:tcp://localhost/~/test"
	username="sa"/>

Now we need to add the actual JTA-related resources, starting with the the TransactionSynchronizationRegistry.
Remembering what I wrote above we have to be aware that the TransactionSynchronizationRegistryFactory will end up at java:comp/env/TransactionSynchronizationRegistry and not at java:comp/TransactionSynchronizationRegistry as the JEE-spec requires.
More on that later.

<Resource
	name="TransactionSynchronizationRegistry"
	auth="Container"
	type="javax.transaction.TransactionSynchronizationRegistry"
	factory="org.objectweb.jotm.TransactionSynchronizationRegistryFactory"/>

The final step is to add the actual transaction manager. In older versions of Tomcat one had to register the JTA-factory as a resource.
Today we got a specialized tag for that.

<Transaction
	factory="org.objectweb.jotm.UserTransactionFactory"
	jotm.timeout="60"/>

The main difference between the Transaction-tag and the Resource-Tag is that the transaction manager will end up at java:comp/UserTransaction, which is the name required by JEE.
That’s it for installing the JOTM as JTA-provider in Tomcat.

To make things available in the web application we need to add a couple of lines to web.xml in our webapplication.

<resource-env-ref>
	<description>DB Connection </description>
	<resource-env-ref-name>jdbc/myDB</resource-env-ref-name>
	<resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
</resource-env-ref>

<resource-env-ref>
	<description>JTA transaction manager</description>
	<resource-env-ref-name>jta/UserTransaction</resource-env-ref-name>
	<resource-env-ref-type>javax.transaction.UserTransaction</resource-env-ref-type>
</resource-env-ref>

<resource-env-ref>
	<description>JTA Transaction Synchronization Registry</description>
	<resource-env-ref-name>TransactionSynchronizationRegistry</resource-env-ref-name>
	<resource-env-ref-type>javax.transaction.TransactionSynchronizationRegistry</resource-env-ref-type>
</resource-env-ref>

Putting it all together

A little example on how to use JTA in your webapplication via spring:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	<property name="dataSource" ref="dataSource"/>
	<property name="jpaVendorAdapter">
		<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
			<property name="showSql" value="false"/>
		</bean>
	</property>
	<propertyname="jpaProperties">
		<props>
			<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</prop>
		</props>
	</property>
</bean>

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/myDB" resource-ref="true"/>

<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
	<property name="transactionSynchronizationRegistryName" value="java:comp/env/TransactionSynchronizationRegistry"/>
	<property name="transactionManagerName" value="java:comp/UserTransaction"/>
</bean>

The only thing I don’t really like about this configuration is this line:

<property name="transactionSynchronizationRegistryName" value="java:comp/env/TransactionSynchronizationRegistry"/>

This is no problem, as long as your only deployment target is Tomcat.

If Tomcat  is only used for local deployments for development and the production system is some sort of JEE-server you will have to change the JNDI-location to the JEE-default.

This is easily achieved using maven-profiles.