EntityManagerHelper
Centralizes access to a single, shared persistence context (typically a
JPA EntityManager) without coupling CoreFx to any
persistence provider. Your application — which already has a JPA
stack — registers a Supplier that produces the manager;
CoreFx stores, lazily creates, caches and hands it back as an opaque object.
Centraliza el acceso a un único contexto de persistencia compartido (típicamente
un EntityManager de JPA) sin acoplar CoreFx a ningún
proveedor de persistencia. Tu aplicación — que ya tiene un stack de
JPA — registra un Supplier que produce el gestor; CoreFx lo
almacena, crea de forma perezosa, cachea y lo devuelve como un objeto opaco.
Why a Supplier, not an EntityManagerPor qué un Supplier, no un EntityManager
CoreFx is a reusable library and must not force a particular persistence
stack (Jakarta Persistence, Hibernate, EclipseLink…) onto its consumers.
Referencing jakarta.persistence.EntityManager directly would
drag that API onto every consumer's classpath. So — exactly like
FlowController's theme
applier — the consuming app passes a Supplier<?>, and the
library depends only on the native Java platform.
CoreFx es una librería reutilizable y no debe forzar un stack de persistencia
concreto (Jakarta Persistence, Hibernate, EclipseLink…) sobre sus consumidores.
Referenciar jakarta.persistence.EntityManager directamente
arrastraría esa API al classpath de cada consumidor. Así que — exactamente como
el aplicador de temas de FlowController —
la app consumidora pasa un Supplier<?>, y la librería depende
únicamente de la plataforma Java nativa.
Quick startInicio rápido
// Once at startup, in YOUR app where jakarta.persistence is available:
EntityManagerHelper.getInstance().initialize(() ->
Persistence.createEntityManagerFactory("myPersistenceUnit")
.createEntityManager());
// Anywhere afterwards — typed retrieval, no cast:
EntityManager em = EntityManagerHelper.getInstance().getManager(EntityManager.class);
em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();
LifecycleCiclo de vida
Registers the factory (called once). The supplier is invoked lazily — the first time a manager is actually requested, and again whenever the cached one is discarded. Throws NullPointerException if the supplier is null, and IllegalStateException if already initialized.Registra la fábrica (se llama una vez). El supplier se invoca de forma perezosa — la primera vez que realmente se solicita un gestor, y de nuevo cada vez que se descarta el cacheado. Lanza NullPointerException si el supplier es null, y IllegalStateException si ya está inicializado.
Returns the shared manager, creating it from the supplier on first access (under a lock, so concurrent first-time callers share one instance). Throws IllegalStateException if not initialized, if the supplier returns null, or if it fails.Devuelve el gestor compartido, creándolo desde el supplier en el primer acceso (bajo un lock, para que los llamantes concurrentes de primera vez compartan una instancia). Lanza IllegalStateException si no está inicializado, si el supplier devuelve null, o si falla.
The recommended accessor. Returns the manager cast to T, so you work with your own type (e.g. EntityManager) without a cast. Throws if not initialized, the supplier misbehaves, or the created manager isn't an instance of type.El accesor recomendado. Devuelve el gestor casteado a T, para que trabajes con tu propio tipo (p. ej. EntityManager) sin cast. Lanza excepción si no está inicializado, si el supplier se comporta mal, o si el gestor creado no es una instancia de type.
Discards the cached manager without closing it, so the next access rebuilds a fresh one. Ownership of the discarded instance returns to you — close it yourself if it holds resources, or use close() instead.Descarta el gestor cacheado sin cerrarlo, para que el siguiente acceso reconstruya uno nuevo. La propiedad de la instancia descartada vuelve a ti — ciérrala tú mismo si retiene recursos, o usa close() en su lugar.
Best-effort shutdown: if the cached manager is AutoCloseable (as JPA EntityManagers are), its close() is called; any exception is swallowed so shutdown never fails. The reference is cleared, but the supplier registration is kept — the helper stays usable.Cierre de mejor esfuerzo: si el gestor cacheado es AutoCloseable (como lo son los EntityManager de JPA), se llama a su close(); cualquier excepción se traga para que el apagado nunca falle. La referencia se limpia, pero el registro del supplier se mantiene — el helper sigue siendo usable.
Whether a manager is currently cached, and whether a supplier has been registered.Si hay un gestor cacheado actualmente, y si se ha registrado un supplier.
Use resetManager() to drop a stale/closed manager and let the next call rebuild one (you own cleanup of the old one). Use close() when you want the helper to close the manager for you. Both leave the supplier in place, so the helper keeps working afterward.Usa resetManager() para soltar un gestor obsoleto/cerrado y dejar que la siguiente llamada reconstruya uno (tú te encargas de limpiar el viejo). Usa close() cuando quieras que el helper cierre el gestor por ti. Ambos dejan el supplier en su lugar, así que el helper sigue funcionando después.
Lazy, thread-safe creationCreación perezosa y thread-safe
Initialization is guarded by double-checked locking and a
volatile flag, mirroring FlowController. The
manager is created lazily on first access under the same lock, so racing
callers never build several instances. Reads after creation are lock-free.
La inicialización está protegida por double-checked locking y un indicador
volatile, reflejando a FlowController. El gestor se
crea de forma perezosa en el primer acceso bajo el mismo lock, así los llamantes
en carrera nunca construyen varias instancias. Las lecturas tras la creación son
lock-free.
By default this caches one manager for the whole process. A JPA EntityManager is not thread-safe, so a single shared instance suits a typical desktop app with one persistence context. If you need isolation (e.g. per task), call resetManager() between units of work, or manage separate managers outside this helper.Por defecto esto cachea un gestor para todo el proceso. Un EntityManager de JPA no es thread-safe, así que una única instancia compartida encaja con una app de escritorio típica con un solo contexto de persistencia. Si necesitas aislamiento (p. ej. por tarea), llama a resetManager() entre unidades de trabajo, o gestiona managers separados fuera de este helper.
RecommendationsRecomendaciones
Do call initialize exactly once at startup, then always retrieve via getManager(EntityManager.class) for a cast-free, type-checked handle.Llama a initialize exactamente una vez al inicio, y luego recupera siempre vía getManager(EntityManager.class) para un handle sin cast y con tipo comprobado.
Do call close() on application shutdown for a clean, best-effort release.Llama a close() al apagar la aplicación para una liberación limpia y de mejor esfuerzo.
Do recover from a closed/stale context with resetManager() rather than re-initializing (which would throw).Recupérate de un contexto cerrado/obsoleto con resetManager() en vez de reinicializar (lo que lanzaría excepción).