Package com.adaptrex.core.persistence.jpa

Source Code of com.adaptrex.core.persistence.jpa.JPAPersistenceManager

/*
* Copyright 2012 Adaptrex, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.adaptrex.core.persistence.jpa;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import javax.xml.parsers.SAXParserFactory;

import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

import com.adaptrex.core.ext.ExtConfig;
import com.adaptrex.core.ext.ExtTypeFormatter;
import com.adaptrex.core.ext.ModelInstance;
import com.adaptrex.core.persistence.PersistenceTools;
import com.adaptrex.core.persistence.api.AdaptrexEntityType;
import com.adaptrex.core.persistence.api.AdaptrexFieldType;
import com.adaptrex.core.persistence.api.AdaptrexPersistenceManager;
import com.adaptrex.core.persistence.api.AdaptrexStoreData;
import com.adaptrex.core.security.SecurityModel;

public class JPAPersistenceManager implements AdaptrexPersistenceManager {

  private static Logger log = Logger.getLogger(JPAPersistenceManager.class);
 
  private EntityManagerFactory factory;
 
  private String name;
 
  Metamodel metaModel;

  /*
   * Create an persistence manager with a specific entity manager factory
   */
  public JPAPersistenceManager(String factoryName) throws IOException {
    if (factoryName == null) {
      List<InputStream> inputStreams;
      try {
        inputStreams = loadResources(
            "META-INF/persistence.xml",
            Thread.currentThread().getContextClassLoader()
          );
      } catch (IOException e) {
        log.warn("Could not find persistence.xml");
        return;
      }

      if (inputStreams.size() > 1) {
        log.warn("Multiple persistence.xml descriptors found but no default has been configured");
        return;
      }

      try {
        DefaultHandler defaultHandler = new DefaultHandler() {
          @Override
          public void startElement(String uri, String localName, String qName, Attributes attributes) {
            if (qName.equalsIgnoreCase("persistence-unit")) name = attributes.getValue("name");
          }
        };
        SAXParserFactory.newInstance().newSAXParser().parse(inputStreams.get(0), defaultHandler);
      } catch (Exception e) {
        log.warn("Could not parse persistence.xml");
        e.printStackTrace();
      }
    } else {
      this.name = factoryName;
    }

    this.factory = Persistence.createEntityManagerFactory(this.name);
    this.metaModel = this.factory.getMetamodel();
   
    try {
      initialize();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    log.info("Creating JPAPersistenceManager for Persistence Unit " + this.name);
  }
 
  public JPAPersistenceManager(EntityManagerFactory emf) {
    this(emf, AdaptrexPersistenceManager.DEFAULT_NAME);
  }
 
  public JPAPersistenceManager(EntityManagerFactory emf, String factoryName) {
    this.factory = emf;
    this.name = factoryName;
    this.metaModel = factory.getMetamodel();
   
    try {
      initialize();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    log.info("Creating JPAPersistenceManager for Persistence Unit " + this.name);   
  }
 
  private Map<String,JPAEntityType> adaptrexEntities;
  private void initialize() throws Exception {
    SecurityModel securityModel = PersistenceTools.getSecurityModel();
    adaptrexEntities = new HashMap<String,JPAEntityType>();
    for (EntityType<?> entityType : metaModel.getEntities()) {
      JPAEntityType jpaEntity = new JPAEntityType(metaModel, entityType, securityModel);
      adaptrexEntities.put(jpaEntity.getName(), jpaEntity);
    }
  }

  @Override
  public AdaptrexEntityType getAdaptrexEntity(String name) {
    return adaptrexEntities.get(name);
  }
 
 
 
  @Override
  public String getName() {
    return this.name;
  }
 
 
  /**
   * Returns an EntityManager for the EntityManagerFactory this persistence manager
   * represents.
   */
  @Override
  public Object getNativeSession() {
    return this.factory.createEntityManager();
  }
 
  EntityManager getEntityManager() {
    return this.factory.createEntityManager();
  }
 
 
  /**
   * Shuts down the EntityManagerFactory this persistence manager uses to generate its
   * ObjectContexts.  This should be called to clean up Cayenne when the container
   * is shut down.
   */
  @Override
  public void shutdown() {
    log.info("Shutting down EntityManagerFactory for " + this.name);
    this.factory.close();
  }

 
  /**
   * Get a persistent entity based on an id for a specific class.
   */ 
  @Override
  public Object getEntity(Class<?> clazz, Object id) {
    EntityManager em = getEntityManager();
    try {
      return em.find(clazz, id);
    } catch (Exception e) {
      return null;
    } finally {
      closeEM(em);
    }
  }

  /**
   * Get a persistent entity based on a key value pair for a specific class.
   */ 
  @Override
  public Object getEntity(Class<?> clazz, String key, Object value) {
    EntityManager em = getEntityManager();
    try {
      return this.getEntity(em, clazz, key, value);
    } catch (Exception e) {
      return null;
    } finally {
      closeEM(em);
    }
  }
 
  /**
   * Get a persistent entity based on an id for a specific class.  This does
   * not automatically close the EntityManager so it needs to be closed by
   * some other method.
   */ 
  private Object getEntity(Object session, Class<?> clazz, Object id) {
    Integer integerId = (id instanceof String) ? Integer.valueOf((String) id) : (Integer) id;
    try {
      return ((EntityManager) session).find(clazz, integerId);
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * Get a persistent entity based on a key value pair for a specific class. 
   * This does not automatically close the EntityManager so it needs to be
   * closed by some other method.
   */   
  private Object getEntity(Object session, Class<?> clazz, String key, Object value) {
    EntityManager em = (EntityManager) session;
    try {
      CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
      CriteriaQuery<?> criteriaQuery = criteriaBuilder.createQuery(clazz);
      criteriaQuery.where(criteriaBuilder.equal(criteriaQuery.from(clazz).get(key), value));
      List<?> result = em.createQuery(criteriaQuery).getResultList();
      return result.size() == 0 ? null : result.get(0);
    } catch (Exception e) {
      return null;
    }
  }
 
 
  @Override
  public AdaptrexStoreData getStoreData(ExtConfig extConfig) {
    return new JPAStoreData(extConfig);
  }
 
  @Override
  public ModelInstance getModelInstance(ExtConfig extConfig, Object id) {
    EntityManager em = getEntityManager();
    try {
      Object entity = this.getEntity(em, extConfig.getEntityClass(), id);
      return new ModelInstance(extConfig, entity);
    } catch (Exception e) {} finally {
      closeEM(em);
    }
    return null;
  }

  @Override
  public ModelInstance getModelInstance(ExtConfig extConfig, String key, Object value) {
    EntityManager em = getEntityManager();
    try {
      Object entity = this.getEntity(em, extConfig.getEntityClass(), key, value);
      return new ModelInstance(extConfig, entity);
    } catch (Exception e) {} finally {
      closeEM(em);
    }
    return null;
  }

  @Override
  public ModelInstance createModelInstance(ExtConfig extConfig, Map<String, Object> data) {
    Object id = null;
    EntityManager em = getEntityManager();
    try {
      AdaptrexEntityType adaptrexEntity = getAdaptrexEntity(extConfig.getClassName());
      Class<?> clazz = extConfig.getEntityClass();
      Object entity = clazz.newInstance();
      this.updateEntity(em, clazz, entity, data, true);
      id = adaptrexEntity.getEntityIdFrom(entity);
    } catch (Exception e) {} finally {
      closeEM(em);
    }
   
    /*
     * Entity doesn't have associations properly loaded in the above entity
     * manager.  Why?  Just grab a new model instance in a new entity manager
     */
    return getModelInstance(extConfig, id);
  }
 
  @Override
  public ModelInstance updateModelInstance(ExtConfig extConfig, Object id, Map<String, Object> data) throws Exception {
    return this.updateModelInstance(extConfig, id, null, null, data);
  }

  @Override
  public ModelInstance updateModelInstance(
      ExtConfig extConfig, String key, Object value, Map<String, Object> data) throws Exception {
    return this.updateModelInstance(extConfig, null, key, value, data);
  }

  private ModelInstance updateModelInstance(
      ExtConfig extConfig, Object id, String key, Object value, Map<String, Object> data) throws Exception {
    EntityManager em = getEntityManager();
    try {
      AdaptrexEntityType adaptrexEntity = getAdaptrexEntity(extConfig.getClassName());
      Class<?> clazz = extConfig.getEntityClass();
      Object entity = id != null ? this.getEntity(em, clazz, id) : this.getEntity(em, clazz, key, value);
      this.updateEntity(em, clazz, entity, data, false);
      id = id != null ? id : adaptrexEntity.getEntityIdFrom(entity);
    } catch (Exception e) {
      throw new Exception(e);
    } finally {
      closeEM(em);
    }
   
    /*
     * Entity doesn't have associations properly loaded in the above entity
     * manager.  Why?  Just grab a new model instance in a new entity manager
     */
    return getModelInstance(extConfig, id);
  }

 
 
  @Override
  public ModelInstance deleteModelInstance(ExtConfig extConfig, Object id) {
    return this.deleteModelInstance(extConfig, id, null, null);
  }
 
  @Override
  public ModelInstance deleteModelInstance(ExtConfig extConfig, String key, Object value) {
    return this.deleteModelInstance(extConfig, null, key, value);
  }
 
  private ModelInstance deleteModelInstance(ExtConfig extConfig, Object id, String key, Object value) {
    EntityManager em = getEntityManager();
    EntityTransaction tx = em.getTransaction();
    try {
      tx.begin();
      Class<?> clazz = extConfig.getEntityClass();
      Object entity = id != null ? this.getEntity(em, clazz, id) : this.getEntity(em, clazz, key, value);
      ModelInstance model = new ModelInstance(extConfig, entity);
      this.evictAssociated(em, entity);
      em.remove(em.merge(entity));
      tx.commit();
      return model;
    } catch (Exception e) {
      tx.rollback();
      log.warn("Error deleting model instance");
    } finally {
      closeEM(em);
    }
    return null;
  }
 
 

  /*
   * Ripped from: http://goo.gl/CYwbl
   */
  private static List<InputStream> loadResources(final String name,
      final ClassLoader classLoader) throws IOException {
    final List<InputStream> list = new ArrayList<InputStream>();
    final Enumeration<URL> systemResources = classLoader.getResources(name);
    while (systemResources.hasMoreElements()) {
      list.add(systemResources.nextElement().openStream());
    }
    return list;
  }
 
 

  private void updateEntity(EntityManager em, Class<?> clazz, Object entity, Map<String,Object> data, boolean isNew) throws Exception {
    AdaptrexEntityType adaptrexEntity = getAdaptrexEntity(clazz.getSimpleName());
   
    EntityTransaction tx = em.getTransaction();
    tx.begin();
   
    try {
      for (String fieldName : data.keySet()) {
        if (fieldName.equals(AdaptrexEntityType.ENTITY_ID_NAME)) continue;
       
        Object newValue = data.get(fieldName);
       
        AdaptrexFieldType adaptrexField = adaptrexEntity.getField(fieldName);
        if (adaptrexField != null) {
          adaptrexField.setValueFor(entity, ExtTypeFormatter.parse(newValue, adaptrexField.getFieldType()));
          continue;
        }
       
        JPAAssociationType adaptrexAssociation = (JPAAssociationType) adaptrexEntity.getAssociationByIdField(fieldName);
        if (adaptrexAssociation != null) {
          adaptrexAssociation.setById(em, entity, newValue);
          continue;
        }
       
        JPACollectionType adaptrexCollection = (JPACollectionType) adaptrexEntity.getCollectionByIdsField(fieldName);
        if (adaptrexCollection != null) {
          adaptrexCollection.setByIds(em, entity, newValue);
        }
      }
     
      tx.commit();
    } catch (Exception e) {
      tx.rollback();
      throw new Exception(e);     
    }
  }
 
 
  private void evictAssociated(EntityManager em, Object entity) {
//    Class<?> clazz = entity.getClass();
//    for (Field field : clazz.getDeclaredFields()) {
//
//      try {
//        Method getter = clazz.getDeclaredMethod("get" + StringUtilities.capitalize(field.getName()));
//       
//        /*
//         * Evict ManyToOne
//         */
//        if (this.isManyToOne(clazz, field.getName())) {
//          Object associated = getter.invoke(entity);
//          if (associated == null) continue;
//          Class<?> assocClass = associated.getClass();
//          this.factory.getCache().evict(
//              assocClass, assocClass.getDeclaredMethod("getId").invoke(associated));
//        }
//
//        /*
//         * Evict OneToMany or ManyToMany
//         */
//        if (this.isOneToMany(clazz, field.getName()) || this.isManyToMany(clazz, field.getName())) {
//          Set<?> associatedSet = (Set<?>) getter.invoke(entity);
//          Class<?> assocClass = null;
//          for (Object associated : associatedSet) {
//            if (assocClass == null) assocClass = associated.getClass();
//            this.factory.getCache().evict(
//                assocClass, assocClass.getDeclaredMethod("getId").invoke(associated));
//          }
//        }
//       
//      } catch (Exception e) {}
//    }
  }
 
 
  private void closeEM(EntityManager em) {
    if (em != null && em.isOpen()) em.close();
  }
}
TOP

Related Classes of com.adaptrex.core.persistence.jpa.JPAPersistenceManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.