package org.cryptocoinpartners.util; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import javax.inject.Inject; import javax.inject.Provider; import javax.persistence.EntityGraph; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.OptimisticLockException; import javax.persistence.Query; import javax.persistence.TypedQuery; import org.cryptocoinpartners.schema.EntityBase; import org.hibernate.TransientObjectException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.persist.Transactional; import com.google.inject.persist.UnitOfWork; /** * <p>Because DI is not always the right idea.</p> * * <p>Conventional wisdom is to inject the EntityManager into classes where you might need it. This * breaks down when you need to perform database access in places where injection is not available. * For example, you may have a polymorphic hierarchy of entity objects that exhibit different data-access * behavior.</p> * * <p>Aspects like persistence (aka transaction) and authorization really fit a thread-local model better. * This static accessor for the EntityManager gives you "always-available" access to the context.</p> */ public class EM { @Inject // @PersistenceContext static Provider<EntityManager> entityManagerProvider; private static final int defaultBatchSize = 20; protected static Logger log = LoggerFactory.getLogger("org.cryptocoinpartners.staticEntityManager"); @Inject protected static UnitOfWork unitOfWork; private static EntityManager em() { return entityManagerProvider.get(); } public static EntityManager getEnityManager() { try { beginUnitOfWork(); return entityManagerProvider.get(); } finally { unitOfWork.end(); } } public static void queryEach(Visitor<Object[]> handler, String queryStr, Object... params) { queryEach(handler, defaultBatchSize, queryStr, params); } @SuppressWarnings("ConstantConditions") public static void queryEach(Visitor<Object[]> handler, int batchSize, String queryStr, Object... params) { EntityManager em = null; try { beginUnitOfWork(); log.trace("namedQueryZeroOne unit of work ended for thread: " + Thread.currentThread()); final Query query = em().createQuery(queryStr); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } query.setMaxResults(batchSize); for (int start = 0;; start += batchSize) { query.setFirstResult(start); List list = query.getResultList(); if (list.isEmpty()) return; for (Object row : list) { if (row.getClass().isArray() && !handler.handleItem((Object[]) row) || !row.getClass().isArray() && !handler.handleItem(new Object[] { row })) return; } } } finally { unitOfWork.end(); log.trace("namedQueryZeroOne unit of work ended for thread: " + Thread.currentThread()); } } // @Transactional public static <T> T namedQueryZeroOne(Class<T> resultType, String namedQuery, Object... params) { try { beginUnitOfWork(); log.trace("namedQueryZeroOne unit of work ended for thread: " + Thread.currentThread()); TypedQuery<T> query = em().createNamedQuery(namedQuery, resultType); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } return query.setHint("org.hibernate.cacheable", true).getSingleResult(); } catch (NoResultException x) { return null; } finally { unitOfWork.end(); log.trace("namedQueryZeroOne unit of work ended for thread: " + Thread.currentThread()); // if (em() != null) // em().close(); } } public static <T> T namedQueryZeroOne(Class<T> resultType, String namedQuery, Map<String, String> properties, Object... params) { try { beginUnitOfWork(); log.trace("namedQueryZeroOne unit of work ended for thread: " + Thread.currentThread()); TypedQuery<T> query = em().createNamedQuery(namedQuery, resultType); for (Map.Entry<String, String> entry : properties.entrySet()) { EntityGraph graph = em().getEntityGraph(entry.getValue()); query.setHint(entry.getKey(), graph); } if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } return query.setHint("org.hibernate.cacheable", false).getSingleResult(); } catch (NoResultException x) { return null; } finally { unitOfWork.end(); log.trace("namedQueryZeroOne unit of work ended for thread: " + Thread.currentThread()); // if (em() != null) // em().close(); } } // @Transactional public static EntityBase find(Map<String, String> properties, EntityBase... entities) { boolean found = true; EntityBase foundEntity = null; try { beginUnitOfWork(); for (EntityBase entity : entities) if (!properties.isEmpty()) { Map hints = new HashMap(); for (Map.Entry<String, String> entry : properties.entrySet()) { EntityGraph graph = em().getEntityGraph(entry.getValue()); hints.put(entry.getKey(), graph); //query.setHint(entry.getKey(), graph); } foundEntity = em().find(entity.getClass(), entity.getId(), hints); } else foundEntity = em().find(entity.getClass(), entity.getId()); if (foundEntity != null) for (EntityBase entity : entities) log.debug(entity.getClass().getSimpleName() + ": " + entity.getId().toString() + " found in database"); else for (EntityBase entity : entities) log.error(entity.getClass().getSimpleName() + ": " + entity.getId().toString() + " not found in database"); return foundEntity; } catch (Exception | Error e) { found = false; log.error("Threw a Execpton or Error in org.cryptocoinpartners.util.persistUtil::insert, full stack trace follows:", e); throw e; //if (PersistUtilHelper.isActive()) // PersistUtilHelper.rollback(); } finally { unitOfWork.end(); } // if (em() != null) // em().close(); } public static <T> T find(Class<T> resultType, UUID id, Map<String, String> properties) { boolean found = true; T foundEntity = null; try { beginUnitOfWork(); if (!properties.isEmpty()) { Map hints = new HashMap(); for (Map.Entry<String, String> entry : properties.entrySet()) { EntityGraph graph = em().getEntityGraph(entry.getValue()); hints.put(entry.getKey(), graph); //query.setHint(entry.getKey(), graph); } foundEntity = (T) em().find(resultType, id, hints); } else foundEntity = em().find(resultType, id); if (foundEntity != null) log.debug(id + " " + resultType.getClass().getSimpleName() + ": found in database"); else log.error(id + " " + resultType.getClass().getSimpleName() + ": not found in database"); return foundEntity; } catch (Exception | Error e) { found = false; log.error("Threw a Execpton or Error in org.cryptocoinpartners.util.persistUtil::insert, full stack trace follows:", e); throw e; //if (PersistUtilHelper.isActive()) // PersistUtilHelper.rollback(); } finally { unitOfWork.end(); } // if (em() != null) // em().close(); } public static EntityBase find(EntityBase... entities) { boolean found = true; EntityBase foundEntity = null; try { beginUnitOfWork(); for (EntityBase entity : entities) foundEntity = em().find(entity.getClass(), entity.getId()); if (foundEntity != null) for (EntityBase entity : entities) log.debug(entity.getClass().getSimpleName() + ": " + entity.getId().toString() + " found in database"); else for (EntityBase entity : entities) log.error(entity.getClass().getSimpleName() + ": " + entity.getId().toString() + " not found in database"); return foundEntity; } catch (Exception | Error e) { found = false; log.error("Threw a Execpton or Error in org.cryptocoinpartners.util.persistUtil::insert, full stack trace follows:", e); throw e; //if (PersistUtilHelper.isActive()) // PersistUtilHelper.rollback(); } finally { unitOfWork.end(); } // if (em() != null) // em().close(); } // @Transactional public static <T> T queryZeroOne(Class<T> resultType, String queryStr, Object... params) { try { beginUnitOfWork(); final TypedQuery<T> query = em().createQuery(queryStr, resultType); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } return query.getSingleResult(); } catch (NoResultException x) { return null; } finally { unitOfWork.end(); // if (em != null) // em.close(); } } // @Transactional public static <T> T queryOne(Class<T> resultType, String queryStr, Map<String, String> properties, Object... params) { // EntityManager em = em(); // try { // try { return sqlQueryOne(resultType, queryStr, params); // PersistUtil.queryOne(Portfolio.class, queryStr, portfolioName); } public static <T> T queryOne(Class<T> resultType, String queryStr, Object... params) { // EntityManager em = em(); // try { // try { return sqlQueryOne(resultType, queryStr, params); // PersistUtil.queryOne(Portfolio.class, queryStr, portfolioName); } // @Transactional public static <T> T sqlQueryOne(Class<T> resultType, String queryStr, Object... params) throws NoResultException { // EntityManager em = em(); T result = null; try { beginUnitOfWork(); log.debug("sqlQueryOne unit of work started for thread: " + Thread.currentThread()); TypedQuery<T> query = em().createQuery(queryStr, resultType); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } result = query.getSingleResult(); return result; } catch (NoResultException e) { // context.getInjector().getInstance(Portfolio.class); // PersistUtil.insert(portfolio); throw e; //return null; } finally { unitOfWork.end(); log.trace("sqlQueryOne unit of work ended for thread: " + Thread.currentThread()); } // em.flush(); // if (em != null) //em.close(); // } } public static <T> T sqlQueryOne(Class<T> resultType, String queryStr, Map<String, String> properties, Object... params) throws NoResultException { // EntityManager em = em(); T result = null; try { beginUnitOfWork(); log.debug("sqlQueryOne unit of work started for thread: " + Thread.currentThread()); TypedQuery<T> query = em().createQuery(queryStr, resultType); for (Map.Entry<String, String> entry : properties.entrySet()) { EntityGraph graph = em().getEntityGraph(entry.getValue()); query.setHint(entry.getKey(), graph); } if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } result = query.getSingleResult(); return result; } catch (NoResultException e) { // context.getInjector().getInstance(Portfolio.class); // PersistUtil.insert(portfolio); throw e; //return null; } finally { unitOfWork.end(); log.trace("sqlQueryOne unit of work ended for thread: " + Thread.currentThread()); } // em.flush(); // if (em != null) //em.close(); // } } //@Transactional public static <T> List<T> namedQueryList(Class<T> resultType, String namedQuery, Object... params) { try { beginUnitOfWork(); log.trace("namedQueryList unit of work ended for thread: " + Thread.currentThread()); TypedQuery<T> query = em().createNamedQuery(namedQuery, resultType); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } return query.setHint("org.hibernate.cacheable", true).getResultList(); } catch (NoResultException x) { return null; } finally { unitOfWork.end(); log.trace("namedQueryList unit of work ended for thread: " + Thread.currentThread()); // if (em() != null) // em().close(); } } public static <T> List<T> namedQueryList(Class<T> resultType, String namedQuery, Map<String, String> properties, Object... params) { try { beginUnitOfWork(); log.trace("namedQueryList unit of work ended for thread: " + Thread.currentThread()); TypedQuery<T> query = em().createNamedQuery(namedQuery, resultType); for (Map.Entry<String, String> entry : properties.entrySet()) { EntityGraph graph = em().getEntityGraph(entry.getValue()); query.setHint(entry.getKey(), graph); } if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } return query.setHint("org.hibernate.cacheable", true).getResultList(); } catch (NoResultException x) { return null; } finally { unitOfWork.end(); log.trace("namedQueryList unit of work ended for thread: " + Thread.currentThread()); // if (em() != null) // em().close(); } } public static <T> List<T> queryList(Class<T> resultType, String queryStr, Object... params) { // EntityManager em = em(); try { beginUnitOfWork(); final TypedQuery<T> query = em().createQuery(queryStr, resultType); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } return query.getResultList(); } catch (TransientObjectException toe) { log.debug("what happened"); return null; } finally { unitOfWork.end(); // em.clear(); // if (em() != null) // em().close(); } } public static <T> List<T> queryList(Class<T> resultType, String queryStr, Map<String, String> properties, Object... params) { // EntityManager em = em(); try { beginUnitOfWork(); final TypedQuery<T> query = em().createQuery(queryStr, resultType); for (Map.Entry<String, String> entry : properties.entrySet()) { EntityGraph graph = em().getEntityGraph(entry.getValue()); query.setHint(entry.getKey(), graph); } // EntityGraph graph = EM.getEnityManager().getEntityGraph("graph.Position.fills"); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } return query.getResultList(); } catch (TransientObjectException toe) { log.debug("what happened"); return null; } finally { unitOfWork.end(); // em.clear(); // if (em() != null) // em().close(); } } // @Transactional public static void insert(EntityBase entity) { // EntityManager em = entityManager.get(); // unitOfWork.begin(); try { beginUnitOfWork(); em().persist(entity); } catch (Exception | Error ex) { throw ex; } finally { unitOfWork.end(); } // em().persist(entity); //em().flush(); //unitOfWork.end(); // TODO Auto-generated method stub } @Transactional private static void update(EntityBase entity) { // EntityManager em = entityManager.get(); em().merge(entity); // TODO Auto-generated method stub } // @Transactional private static void evict(EntityBase entity) { // EntityManager em = entityManager.get(); beginUnitOfWork(); em().detach(entity); unitOfWork.end(); // TODO Auto-generated method stub } //@Transactional // @Transactional public static void persist(EntityBase... entities) { // unitOfWork.begin(); for (EntityBase entity : entities) { // unitOfWork.begin(); try { insert(entity); } //entityManager.get().flush(); //entityManager.get().getTransaction().commit(); // log.debug("persisting entity " + entity.getClass().getSimpleName() + " " + entity); // entityManager.get().getTransaction().commit(); // } catch (OptimisticLockException ole) { // log.error("Unable to merge record" + ole); // } catch (Exception | Error ex) { System.out.println("Unable to perform request in " + EM.class.getSimpleName() + ":persist, full stack trace follows:" + ex); // ex.printStackTrace(); // } finally { // unitOfWork.end(); // } } } } // @Transactional public static void merge(EntityBase... entities) { for (EntityBase entity : entities) try { update(entity); // em().flush(); //entityManager.get().flush(); //entityManager.get().getTransaction().commit(); // log.debug("persisting entity " + entity.getClass().getSimpleName() + " " + entity); // entityManager.get().getTransaction().commit(); } catch (OptimisticLockException ole) { log.error("Unable to merge record" + ole); } catch (Exception | Error ex) { System.out.println("Unable to perform request in " + EM.class.getSimpleName() + ":persist, full stack trace follows:" + ex); ex.printStackTrace(); } } // @Transactional // @com.google.inject.persist.Transactional public static void beginUnitOfWork() { //try { unitOfWork.begin(); //} catch (IllegalStateException ex) { // unitOfWork.end(); //unitOfWork.begin(); // } } public static void detach(EntityBase... entities) { for (EntityBase entity : entities) try { //evict(entity); //entityManager.get().flush(); //entityManager.get().getTransaction().commit(); // log.debug("persisting entity " + entity.getClass().getSimpleName() + " " + entity); // entityManager.get().getTransaction().commit(); } catch (OptimisticLockException ole) { log.error("Unable to detach record" + ole); } catch (Exception | Error ex) { System.out.println("Unable to perform request in " + EM.class.getSimpleName() + ":persist, full stack trace follows:" + ex); ex.printStackTrace(); } } // @Transactional public static <T> void queryEach(Class<T> resultType, Visitor<T> handler, String queryStr, Object... params) { queryEach(resultType, handler, defaultBatchSize, queryStr, params); } // @Transactional public static <T> T find(Class<T> resultType, UUID id) { try { beginUnitOfWork(); return em().find(resultType, id); } finally { unitOfWork.end(); } } // @Transactional public static <T> T namedQueryOne(Class<T> resultType, String namedQuery, Object... params) throws NoResultException { try { // unitOfWork. beginUnitOfWork(); final TypedQuery<T> query = em().createNamedQuery(namedQuery, resultType); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } return query.getSingleResult(); } catch (Exception | Error ex) { // System.out.println("Unable to perform request in " + EM.class.getSimpleName() + ":persist, full stack trace follows:" + ex); // ex.printStackTrace(); throw ex; // return null; } finally { unitOfWork.end(); } } // @Transactional public static <T> void queryEach(Class<T> resultType, Visitor<T> handler, int batchSize, String queryStr, Object... params) { try { beginUnitOfWork(); final TypedQuery<T> query = em().createQuery(queryStr, resultType); if (params != null) { for (int i = 0; i < params.length; i++) { Object param = params[i]; query.setParameter(i + 1, param); // JPA uses 1-based indexes } } query.setMaxResults(batchSize); for (int start = 0;; start += batchSize) { query.setFirstResult(start); final List<T> list = query.getResultList(); if (list.isEmpty()) return; for (T row : list) { if (!handler.handleItem(row)) return; } } } finally { unitOfWork.end(); // if (em() != null) // em().close(); } } }