gwt code-injection cdi entitymanager requestfactory

GWT RequestFactory: cómo usar EntityManager individual por solicitud



code-injection cdi (3)

Si está utilizando Spring, solo necesita agregar un filtro de servlet OpenEntityManagerInView a su web.xml.

<filter> <filter-name>entityManagerFilter</filter-name> <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>entityManagerFilter</filter-name> <url-pattern>/gwtRequest</url-pattern> </filter-mapping>

Para que RequestFactory persista en las entidades adjuntas , debo asegurarme de usar el mismo EntityManager para cada solicitud.

Construí mi propia clase de fábrica para esto basada en una implementación de ThreadLocal , pero no estoy seguro de cómo liberar adecuadamente los recursos (por ejemplo, cómo saber que la solicitud ha finalizado y llamar a close() ).

¿Existe una forma sencilla de garantizar que se utilice un solo EntityManager en una ServletRequest dada sin recurrir a J2EE / CDI completo? Tomaré esa ruta si es necesario, pero esperaba mantener las cosas simples, especialmente porque me gustaría seguir usando el servidor de desarrollo liviano que viene con GWT.


La aplicación de muestra DynaTableRf hace algo similar al agregar un filtro de servlet para configurar un contexto de persistencia en su archivo web.xml . Alternativamente, podría subclase RequestFactoryServlet y anular su método doPost() para derribar EntityManager en un bloque super.doPost() cuando se super.doPost() .


Esto es lo que finalmente surgió, basado en los comentarios del Grupo de Google GWT, y BobV .

Cree un titular local de threads para EntityManager; haga referencia a esto en sus entidades cuando necesiten obtener un EntityManager:

public class ThreadLocalEntityManager { private static ThreadLocal<EntityManager> holder = new ThreadLocal<EntityManager>(); private ThreadLocalEntityManager() { } public static EntityManager get() { return holder.get(); } public static void set(EntityManager em) { holder.set(em); } }

A continuación, cree un filtro que establecerá el EntityManager inicial para la solicitud:

public class PersistenceFilter implements Filter { protected static final Logger log = Logger.getLogger(PersistenceFilter.class.getName()); private EntityManagerFactory factory; @Override public void init(FilterConfig filterConfig) throws ServletException { factory = Persistence.createEntityManagerFactory("my_persistence"); } @Override public void destroy() { factory.close(); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { EntityManager em = factory.createEntityManager(); ThreadLocalEntityManager.set(em); EntityTransaction tx = em.getTransaction(); tx.begin(); try { chain.doFilter(req, res); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { log.info("closing EntityManager: " + EMF.entityManager()); em.close(); } } }

A continuación, aplique el filtro al patrón URL / gwtRequest:

<filter> <filter-name>PersistenceFilter</filter-name> <filter-class>com.example.PersistenceFilter</filter-class> </filter> <filter-mapping> <filter-name>PersistenceFilter</filter-name> <url-pattern>/gwtRequest</url-pattern> </filter-mapping>

Tenga en cuenta que aquí hay un error: se crea un EntityManager para cada solicitud que pasa por este servlet, ya sea que lo use su código subyacente o no. Probablemente podría hacerse más robusto y de alguna manera crear el EntityManager (y la transacción) de forma perezosa solo cuando se solicite.

Pero hasta ahora este código parece funcionar bien con RequestFactory . Sugerencias para mejoras muy bienvenidas.

Nota: esta experiencia me ha enseñado que probablemente vale la pena pasar al CDI completo en lugar de tratar de implementar piezas como este. Simplemente no tuve el tiempo disponible para tal movimiento durante este proyecto.