Si quieres ver este artículo en inglés, lo tienes disponible aquí.
Pues bien, los hechos:
En definitiva, si no queréis tener problemas y queréis usar un código que puedan utilizar tanto GWT como las llamadas a servicios web a través de Axis, podríais usar un código como el siguiente:
- En primer lugar, así como el EntityManagerFactory puede ser compartido por diferentes objetos (e hilos), el EntityManager no puede ser compartido entre diferentes threads. Esto está especificado en JPA, pero no le das importancia hasta que empiezas a usar JPA desde la web (que será el caso más habitual).
- En segundo lugar, Axis crea un nuevo objeto (e hilo) por cada petición que entra al servidor.
- En tercero, y al contrario que con Axis, al utilizar uno de los llamados servicio remotos de servidor del GWT se crea un objeto (y thread) que es posteriormente reutilizado cada vez que se llama a dicho servicio. Es decir, no se crea uno nuevo por cada uno que entra.
- Si utilizamos un objeto EntityManager estático en una llamada a Axis, el código fallará en el momento en que dos hilos se crucen (bastante normal en la web), al utilizar el mismo objeto los 2.
- En el caso de GWT, al contrario que en Axis, no es necesario que el EntityManager sea estático para que de problemas (que también los dará, claro); bastará con que sea un atributo global dentro del objeto que implementa el servicio remoto. Al ser un objeto único el que responde a las peticiones, 2 llamadas al servidor utilizarán el mismo EntityManager y esto hará que código falle.
- Un servicio de Axis deberá, por tanto, crear un nuevo EntityManager, y éste no podrá ser estático.
- Cada método de un servicio remoto de GWT tiene que crear un nuevo EntityManager para uso individual (no vale que lo cree el objeto a nivel global, ver punto 2. Si no lo hace, 2 llamadas simultáneas al mismo servicio remoto utilizarán a la vez el mismo EntityManager, dando inmediatamente lugar a excepciones.
El EntityManagerFactory sí puede ser compartido por los diferentes hilos.
En definitiva, si no queréis tener problemas y queréis usar un código que puedan utilizar tanto GWT como las llamadas a servicios web a través de Axis, podríais usar un código como el siguiente:
public class JPAManager {
private final static EntityManagerFactory emf =
Persistence.createEntityManagerFactory("JPAImplementationTest");
private EntityManager em = emf.createEntityManager();
public EntityManager getEntityManager () {
return em;
}
}
private EntityManager em = emf.createEntityManager();
public EntityManager getEntityManager () {
return em;
}
}
Cada método llamado en la invocación del web service o del servicio remoto de servidor de GWT deberá crear su propio JPAManager. De esta forma, os evitáis tener problemas entre los diferentes hilos creados en las invocaciones.
Se pueden usar métodos más sofisticados, como implementar un singleton o usar el ServletContextListener, como ha puesto alguno en los comentarios. Pero lo cierto es que este sencillo método funcionó y resistió algunas pruebas de carga.
No hay comentarios:
Publicar un comentario