In my experience with the three technologies which appear in the title of this article, I had to face a number of problems, actually quite easy to solve once you know what all is about.
So I decided to publish this, for others not to have to face these same problems.
Here you have some lessons learned that should be taken into account when working with the Google Web Toolkit, Axis and any of the JPA implementations out there.
You have this same article in Spanish here.
These are the facts:
- EntityManager can not be shared among threads. This is specified in JPA, but you don't give it enough importance until you start using JPA from the web (which will probably be the usual case).
- Second, Axis creates a new object (and thread) for each call to the server.
- Third, contrary to Axis, when you use one of the so-called GWT server remote services, only one object and thread are created and this object is reused everytime the remote service is called. That is to say, GWT does not create a new object for every new call.
As a result of these facts, we have these consequences:
- If we use a static EntityManager in a call to Axis, the code will fail as soon as two threads cross with each other (quite usual in a web application), given that they will be using the same EntityManager object.
- Contrary to Axis, in the case of GWT it is not necessary that EntityManager is static to start generating problems; it will be enough that it is a global attribute belonging to the object that implements the GWT remote service. Being one only object that answers all petitions, two calls to the server will use the same EntityManager and this will make the code fail.
So, we can conclude two rules:
- An Axis service must therefore create a new EntityManager and this can not be static.
- Each method of a GWT remote service must create a new EntityManager for individual use (it is not enough that it creates it at a global level).
Unfortunately, JPA exceptions are not especially explicit. This is common to almost every implementation of JPA: they give almost no concrete information (including Hibernate).
The EntityManagerFactory can and should be shared among different threads, given that it is a quite expensive object to create.
In short, if you don't want to have problems and you would like to have a piece of code that can be used both by GWT and Axis, you could write something like this:
public class JPAManager {
private final static EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JPAImplementationTest");
private EntityManager em = emf.createEntityManager();
public EntityManager getEntityManager () {
return em;
}
}Each method called in an invocation to a web service or to a GWT server remote service should create its own JPAManager and get the EntityManager with the public method. This way you will avoid having problems among the different threads created in the invocations.
You could also use more sophisticated solutions like implementing a singleton (with the problems associated to them) or using the ServletContextListener, as someone suggested in the comments. But this simple solution worked for me and resisted some load tests.
You could also use more sophisticated solutions like implementing a singleton (with the problems associated to them) or using the ServletContextListener, as someone suggested in the comments. But this simple solution worked for me and resisted some load tests.