I worked with a colleague, Xavier, to build a kind of « best of breed » Web 2.0 technologies project template that we could reuse from project to project.
Our aim for this project was to :
- build a simple Web 2.0 project based on the technologies or libraries we like to use in Java EE today’s world (GWT, Spring, JPA/Hibernate, Acegi, Maven)
- and to create a Maven archetype (as we didn’t found anyone which already provides integration of these technologies together).
Let’s consider the following architecture : we have an existing domain model and a traditionnal multilayered application (business layer, data access layer, database), and we want to be able to use GWT as the presentation layer.
Basically, points we wanted to take into consideration were :
- how can GWT interact with Spring ?
- managing Hibernate lazy collections.
- how can Acegi be used to improve security of such a GWT based application ?
A Maven based project
We’ve started using the archetype gwt-archetype.
This archetype provides a Maven based project with a simple GWT client.
With the gwt plugin maven-googlewebtoolkit2-plugin, we are able to launch the GWT Debug Console and also the embedded Jetty container with the Jetty plugin for Maven.
GWT / Spring communication
Several scenarii are available to integrate GWT and Spring.
We have tested 2 of them :
Strong integration , following Chris Lee’s post GWT-RPC with Spring 2.x.
GWT services are beans, configured in the Spring context. You annotate them with a custom annotation
Then you write your own class extending Spring’s
AbstractDetectingUrlHandlerMapping class. Its role is to detect the annotation and to generate urls that will be handled by Spring and mapped to corresponding ‘controller’.
Finally, you write an another class that extends
RemoteServiceServlet (provided by GWT) which is responsible to handle RPC calls.
This first approach looks good for IoC purists : GWT services are not servlets, and you can even think about using your business layer as GWT endpoints.
But is this really a good idea ? It seems like a violation of SoC paradigm, isn’t it … ?
Whatever, when considering the use of Hibernate, that also needs to rewrite parts of
RemoteServiceServlet, you come into troubles …
So we have finally choosen a kind of light integration : GWT services simply get business service implementations from context.
init() method, GWT endpoints – that extend
Servlet by inheritance – get their dependencies from the context.
BeanFactory factory = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
taskManager = (TaskManager) factory.getBean("taskManager");
Don’t be offended (as we initially were !) by this approach : just consider GWT layer as a presentation layer which comes on top of an existing Spring multilayered architecture, as we mentioned in the intro.
GWT / Hibernate communication
We wanted to use Hibernate as an implementation of JPA specification for differents reasons : convention over configuration, choice for implementation, standard use.
At the time we had chosen to use the freshest GWT build which was a pre-release of version 1.5 since it supports Java 1.5 features : annotations, generics.
However, we can’t use our Hibernate objects directly.
As we can read in the post Why GWT 1.5 won’t solve your Hibernate issues : « Hibernate POJO are not real POJO. The persistence library adds a lot of needed information, such as session factory, by creating a dynamic proxy (with CGLIB or Javassist) around your instance. When you manipulate an Hibernate POJO, you do not do it with an instance of your class, but with a instrumented, derived one! »
As a consequence, we have to duplicate our domain model. One domain for backend processes (typically POJOs with JPA annotations), and one other domain for GWT serialization processes (DTOs).
As managing this duplication can sound bad, we have chosen hibernate4gwt, a library that can help us managing this.
As you can read in its documentation, hibernate4gwt offers different ways to manage domain model duplication : stateless, dynamic proxy, Java5 support and stateful.
Since dynamic proxy seems to be the less intrusive for our POJOs, it gained our preference.
(Moreover, with 1.5 GWT pre-release, we can use our 1.5 annotated POJOs.)
Initially we wanted to use stateless mode, but having unresolved issues with
StatelessPojoStore down the road we decided to use
May look like a hack but it worked and allowed to avoid building in-house code.
More importantly we thought duplicating the domain objects could be an error prone task.
Then we started to focus on security.
Considering using Acegi in a GWT project gives us 2 solutions.
We have tried to use a HTML form to authenticate. This is simple but is incompatible with the use of GWT console to debug the application. Effectively, GWT Console needs a GWT module to run, it doesn’t want to know anything about html pages.
So to be able to debug our application in the GWT console, we have preferred the second approach which in fact is to use a second GWT Login component : a single
EntryPoint which declares a
FormPanel, which posts to
We have included a simple Acegi configuration file : if you are not authenticated, it enforces you to login by redirecting you to the login module.
Authentication is made upon the database with a
DaoAuthenticationProvider, which takes as a parameter a custom implementation of
UserDetailsService. This one uses the service layer to look for the users in the database.
More informations :
How to build the project : https://opensource.fastconnect.org/redmine/wiki/spring-gwt-archetype
Sources : http://opensource.fastconnect.org/svn/toolbox/maven2/archetypes/hibernate-spring-gwt-archetype/trunk/