/*
* 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_old;
import com.adaptrex.core.ext.Filter;
import com.adaptrex.core.ext.Sorter;
import com.adaptrex.core.utilities.StringUtilities;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.persistence.Cache;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JpaPersistence {
private EntityManagerFactory factory;
private Map<String, Class<?>> entityClassCache = new HashMap<String, Class<?>>();
private Map<String, List<String>> memberAnnotationCache = new HashMap<String, List<String>>();
private Map<String, String> fieldTypeCache = new HashMap<String, String>();
private Logger log = LoggerFactory.getLogger(JpaPersistence.class);
private static SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd");
public JpaPersistence(EntityManagerFactory factory) {
this.factory = factory;
}
public Class<?> getEntityClass(String className) {
try {
if (entityClassCache.containsKey(className)) {
return entityClassCache.get(className);
}
EntityManager em = factory.createEntityManager();
Metamodel meta = em.getMetamodel();
for (EntityType<?> et : meta.getEntities()) {
if (et.getJavaType().getName().endsWith("." + className)) {
Class<?> clazz = et.getJavaType();
entityClassCache.put(className, clazz);
return clazz;
}
}
} catch (Exception e) {
log.warn("Error", e);
}
return null;
}
/* *******************************************************************
*
* Get Single Entity
*/
// public Object getEntity(AdaptrexSession session, String entityName,
// Integer id) {
// EntityManager em = (EntityManager) session.getPersistence()
// .getNativeSession();
// return em.find(getEntityClass(entityName), id);
// }
//
// public Object getEntity(AdaptrexSession session, Class<?> clazz, Integer id) {
// EntityManager em = (EntityManager) session.getPersistence()
// .getNativeSession();
// return em.find(clazz, id);
// }
/* *******************************************************************
*
* Save Single Entity
*/
// public Object saveEntity(AdaptrexSession session, Object entity) {
// EntityManager em = (EntityManager) session.getPersistence()
// .getNativeSession();
// Integer id = null;
// try {
// Method idGetter = entity.getClass().getDeclaredMethod("getId");
// id = (Integer) idGetter.invoke(entity);
// } catch (Exception e) {
// log.debug("Couldn't find id for entity");
// return entity;
// }
//
// EntityTransaction tx = em.getTransaction();
// tx.begin();
//
// if (id != null && em.find(entity.getClass(), id) != null) {
// log.debug("Merging entity: " + entity.getClass().getSimpleName());
// entity = em.merge(entity);
// } else {
// em.persist(entity);
// log.debug("Persisting entity: " + entity.getClass().getSimpleName());
// }
//
// /*
// * Evict related objects from cache
// */
// try {
// evictAssociated(em, entity);
// } catch (Exception e) {
// log.warn("Error: ", e);
// }
//
// tx.commit();
// return entity;
// }
private void evictAssociated(EntityManager em, Object entity) {
Class<?> clazz = entity.getClass();
for (Field field : clazz.getDeclaredFields()) {
/*
* Evict ManyToOne
*/
if (isManyToOne(clazz, field.getName())) {
try {
Method getter = clazz.getDeclaredMethod("get"
+ StringUtilities.capitalize(field.getName()));
Object associated = getter.invoke(entity);
if (associated == null) {
continue;
}
Class<?> associatedClazz = associated.getClass();
Method idGetter = associatedClazz
.getDeclaredMethod("getId");
EntityManagerFactory emf = em.getEntityManagerFactory();
Cache emfCache = emf.getCache();
emfCache.evict(associated.getClass(),
idGetter.invoke(associated));
} catch (Exception e) {
log.warn("Error", e);
}
}
/*
* Evict OneToMany TODO: Test This
*/
if (isOneToMany(clazz, field.getName())) {
try {
Method getter = clazz.getDeclaredMethod("get"
+ StringUtilities.capitalize(field.getName()));
Set<?> associatedSet = (Set<?>) getter.invoke(entity);
for (Object associated : associatedSet) {
Class<?> associatedClazz = associated.getClass();
Method idGetter = associatedClazz
.getDeclaredMethod("getId");
em.getEntityManagerFactory()
.getCache()
.evict(associated.getClass(),
idGetter.invoke(associated));
}
} catch (Exception e) {
log.warn("Error", e);
}
}
}
}
/* *******************************************************************
*
* Delete Single Entity
*/
// public Object deleteEntity(AdaptrexSession session, Object entity) {
// EntityManager em = (EntityManager) session.getPersistence()
// .getNativeSession();
// EntityTransaction tx = em.getTransaction();
// tx.begin();
// em.remove(em.merge(entity));
//
// /*
// * Evict related objects from cache
// */
// evictAssociated(em, entity);
//
// tx.commit();
// return entity;
// }
/* *******************************************************************
*
* Entity List
*/
@SuppressWarnings("unchecked")
public List<Object> getEntityList() {
// List<Object> list = new ArrayList<Object>();
// try {
//// EntityManager em = (EntityManager) session.getPersistence()
//// .getNativeSession();
//
// Map<String, Object> parameters = new HashMap<String, Object>(
// config.getParams());
//
// Class<?> clazz = config.getClazz();
// String className = clazz.getSimpleName();
// String alias = className.toLowerCase().substring(0, 1);
//
// /*
// * Core JPQL
// */
// String jpql = "SELECT " + alias + " FROM " + className + " "
// + alias;
//
// /*
// * Where
// */
// String where = "";
// if (config.getWhere() != null) {
// where += config.getWhere();
// }
//
// /*
// * Filter
// */
// for (Filter filter : config.getFilters()) {
// if (!where.isEmpty()) {
// where += " AND ";
// }
//
// String val = String.valueOf(filter.getValue());
// String prop = filter.getProperty();
// String param = prop.replace(".", "_");
//
// /*
// * Handle between inclusive
// */
// if (val.contains(">=<")) {
// String[] filterParts = val.split(">=<");
//
// where += "(" + alias + "." + prop + " BETWEEN :" + param
// + "_low AND :" + param + "_high)" + "";
// parameters.put(param + "_low", filterParts[0]);
// parameters.put(param + "_high", filterParts[1]);
//
// /*
// * Handle "OR"
// */
// } else if (val.contains("||")) {
// String whereOr = "";
// int i = 1;
//
// for (String orPart : val.split("\\|\\|")) {
// whereOr += whereOr.isEmpty() ? "(" : " OR ";
// whereOr += alias + "." + prop + " = :" + param + i;
// parameters.put(param + i, orPart);
// i++;
// }
// whereOr += ")";
// where += whereOr;
//
// } else {
// String eqType = val.contains("%") ? " like " : " = ";
// if (eqType.contains("like")) {
// where += "lower(" + alias + "." + prop + ")" + eqType
// + ":" + param;
//
// } else {
// where += alias + "." + prop + eqType + ":" + param;
// }
//
// parameters.put(param, val);
// }
// }
//
// /*
// * Add where clause
// */
// if (!where.isEmpty()) {
// jpql += " WHERE " + where;
// }
//
// if (config.getSorters().size() > 0) {
// String sortClause = "";
// for (Sorter sorter : config.getSorters()) {
// if (!sortClause.isEmpty()) {
// sortClause += ",";
// }
// sortClause += alias + "." + sorter.getProperty() + " "
// + sorter.getDirection();
// }
// jpql += " ORDER BY " + sortClause;
// }
//
// log.debug("JPQL: " + jpql);
// Query q = null;// = em.createQuery(jpql, clazz);
//
// /*
// * Add params TODO: This is tedius... we want to automatically
// * determine the type for the field we're trying to set the
// * parameter for
// */
// for (String key : parameters.keySet()) {
// Object paramObj = parameters.get(key);
//
// Class<?> paramType = q.getParameter(key).getParameterType();
// String typeName = paramType.getSimpleName().toLowerCase();
//
// try {
// if (typeName.equals("boolean")) {
// String stringVal = (String) paramObj;
// paramObj = stringVal.equals("1")
// || stringVal.equals("true")
// || stringVal.equals("Y");
//
// } else if (typeName.equals("date")) {
// paramObj = dateFormat.parse((String) paramObj);
//
// } else {
// Method m = paramType.getDeclaredMethod("valueOf",
// String.class);
// paramObj = m.invoke(null, paramObj);
// }
// } catch (Exception e) {
// }
//
// log.debug(" Param: " + key + " = " + paramObj);
// q.setParameter(key, paramObj);
// }
//
// //store.setTotalCount(q.getResultList().size());
//
// if (config.getPageSize() != null) {
// q.setMaxResults(config.getPageSize());
// }
// if (config.getStart() != null) {
// q.setFirstResult(config.getStart());
// }
// //list = q.getResultList();
// } catch (Exception e) {
// log.warn("Error", e);
// }
return null;
}
/* ************************************************************************************
*
* Everything below this is experimental. Possibly moved under a separate
* interface
*/
public boolean isIdField(Class<?> clazz, String fieldName) {
return hasMemberAnnotation(clazz, fieldName, "Id");
}
/*
* TODO: Do we want to move ManyToMany to a separate method?
*/
public boolean isOneToMany(Class<?> clazz, String fieldName) {
return hasMemberAnnotation(clazz, fieldName, "OneToMany")
|| hasMemberAnnotation(clazz, fieldName, "ManyToMany");
}
public boolean isManyToOne(Class<?> clazz, String fieldName) {
return hasMemberAnnotation(clazz, fieldName, "ManyToOne");
}
public Object getFieldValue(Object entity, String fieldName) {
Method getter = null;
Class<?> clazz = entity.getClass();
try {
getter = clazz.getMethod("get" + capitalize(fieldName));
} catch (Exception e) {
}
if (getter == null) {
try {
getter = clazz.getMethod("is" + capitalize(fieldName));
} catch (Exception e) {
}
}
if (getter == null) {
return null;
}
try {
return getter.invoke(entity);
} catch (Exception e) {
log.warn("Error", e);
return null;
}
}
public String getFieldType(Class<?> clazz, String fieldName) {
String fieldType = fieldTypeCache
.get(clazz.getName() + "." + fieldName);
if (fieldType != null)
return fieldType;
Field field = null;
try {
field = clazz.getDeclaredField(fieldName);
} catch (Exception e) {
}
if (field == null)
return null;
String columnType = field.getType().getSimpleName().toLowerCase();
if (columnType.equals("integer") || columnType.equals("long")) {
columnType = "int";
} else if (columnType.equals("double")) {
columnType = "float";
} else if (columnType.equals("time")) {
columnType = "time";
} else if (columnType.equals("calendar") || columnType.equals("date")) {
columnType = "date";
}
if (columnType.equals("date")) {
Temporal a = field.getAnnotation(Temporal.class);
if (a == null) {
try {
Method getter = clazz.getMethod("get"
+ StringUtilities.capitalize(fieldName));
if (getter != null) {
a = getter.getAnnotation(Temporal.class);
}
} catch (Exception e) {
}
}
if (a != null && a.value().equals(TemporalType.TIME)) {
columnType = "time";
}
}
fieldTypeCache.put(clazz.getName() + "." + fieldName, columnType);
return columnType;
}
private boolean hasMemberAnnotation(Class<?> clazz, String member,
String annotationName) {
List<String> memberAnnotations = memberAnnotationCache.get(clazz
.getName() + "." + member);
if (memberAnnotations == null) {
memberAnnotations = getMemberAnnotations(clazz, member);
}
return memberAnnotations.contains(annotationName);
}
/*
* This gets a list of all annotations on a class field (or it's getter)
*/
private List<String> getMemberAnnotations(Class<?> clazz, String member) {
List<String> list = memberAnnotationCache.get(clazz.getName() + "."
+ member);
if (list != null) {
return list;
}
list = new ArrayList<String>();
try {
Field field = clazz.getDeclaredField(member);
if (field != null) {
for (Annotation annotation : field.getDeclaredAnnotations()) {
list.add(annotation.annotationType().getSimpleName());
}
}
} catch (Exception e) {
}
try {
Method getter = clazz.getMethod("get"
+ StringUtilities.capitalize(member));
if (getter != null) {
for (Annotation annotation : getter.getDeclaredAnnotations()) {
list.add(annotation.annotationType().getSimpleName());
}
}
} catch (Exception e) {
}
memberAnnotationCache.put(clazz.getName() + "." + member, list);
return list;
}
private static String capitalize(String string) {
return string.substring(0, 1).toUpperCase() + string.substring(1);
}
public Object getFactory() {
return this.factory;
}
public Object getNativeSession() {
return this.factory.createEntityManager();
}
public void closeNativeSession(Object entityManager) {
((EntityManager) entityManager).close();
}
}