Java tutorial
/* * Copyright 2012 Eng Kam Hon (kamhon@gmail.com) * * 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 net.kamhon.ieagle.dao; import java.beans.PropertyDescriptor; import java.io.Serializable; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.persistence.Transient; import net.kamhon.ieagle.datagrid.DatagridModel; import net.kamhon.ieagle.datagrid.Filter; import net.kamhon.ieagle.datagrid.Sorter; import net.kamhon.ieagle.exception.DataException; import net.kamhon.ieagle.util.CollectionUtil; import net.kamhon.ieagle.util.ReflectionUtil; import net.kamhon.ieagle.vo.VoBase; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; import org.springframework.dao.DataAccessException; import org.springframework.util.Assert; public class Jpa2Dao<T, PK extends Serializable> { private static final Log log = LogFactory.getLog(Jpa2Dao.class); private T t; @PersistenceContext private EntityManager em; public Jpa2Dao(T t) { this.t = t; } public void delete(T object) { em.remove(object); } public void deleteAll(Set<T> set) { for (T object : set) { em.remove(object); } } public void save(T object) { em.persist(object); } public void saveAll(Set<T> set) { for (T object : set) { em.persist(object); } } public void saveAll(T... objects) { for (T object : objects) { em.persist(object); } } public void update(T object) { em.merge(object); } public void updateInsert(T object) { em.persist(object); } @SuppressWarnings("unchecked") public T get(PK serializablekey) { return em.find((Class<T>) t.getClass(), serializablekey); } @SuppressWarnings("unchecked") public T getReadonly(final PK serializablekey) { return em.find((Class<T>) t.getClass(), serializablekey, LockModeType.OPTIMISTIC); } @SuppressWarnings("unchecked") public T getForUpdate(final PK serializablekey) { return em.find((Class<T>) t.getClass(), serializablekey, LockModeType.PESSIMISTIC_WRITE); } public List<T> loadAll() { return find("select o from " + t.getClass().getName() + " o "); } public List<T> findQueryAsList(String query, Object... objectArray) { query = convertJpaPositionParams(query); return find(query, objectArray); } public List<T> findQueryNameAsList(String queryName, Object... objectArray) { return findByNamedQuery(queryName, objectArray); } public T findFirst(String query, Object... objectArray) { query = convertJpaPositionParams(query); List<T> list = findBlock(query, 0, 1, objectArray); if (list.size() > 0) return list.get(0); else return null; } public T findFirst(T example, String... orderBy) { QueryParams queryParams = translateExampleToQueryParams(example, orderBy); return findFirst(queryParams.query, queryParams.params.toArray()); } public T findFirstByExample(T example, List<String> orderBy) { if (CollectionUtil.isNotEmpty(orderBy)) return findFirst(example, orderBy.toArray(new String[0])); else return findFirst(example); } @SuppressWarnings("unchecked") public T findUnique(String query, final Object... objectArray) { final String query2 = convertJpaPositionParams(query); Query q = em.createQuery(query2); for (int i = 0; i < objectArray.length; i++) { q.setParameter(i + 1, objectArray[i]); } return (T) q.getSingleResult(); } public T findUnique(T example) { QueryParams queryParams = translateExampleToQueryParams(example); return findFirst(queryParams.query, queryParams.params.toArray()); } @SuppressWarnings("unchecked") public List<T> findBlock(String query, final int offset, final int recordCount, final Object... objectArray) { final String query2 = convertJpaPositionParams(query); Query q = em.createQuery(query2); for (int i = 0; i < objectArray.length; i++) { q.setParameter(i + 1, objectArray[i]); } q.setFirstResult(offset); q.setMaxResults(recordCount); return q.getResultList(); } @SuppressWarnings("unchecked") public void findForDatagrid(DatagridModel<T> datagridModel, String alias, String queryString, Object... objectArray) { findForDatagrid(datagridModel, alias, queryString, null, objectArray); } @SuppressWarnings("unchecked") public void findForDatagrid(DatagridModel<T> datagridModel, String alias, String queryString, String countQueryString, Object... objectArray) { boolean hasCountQueryString = StringUtils.isNotBlank(countQueryString); String countQuery = ""; queryString = convertJpaPositionParams(queryString); Assert.isTrue(StringUtils.isNotBlank(alias), "The alias can not be BLANK!!"); Assert.isTrue(StringUtils.isNotBlank(queryString), "The queryString can not be BLANK!!"); if (CollectionUtil.isNotEmpty(datagridModel.getFilters())) { Assert.doesNotContain(queryString, BasicDao.FILTER_PARAMS, "The " + BasicDao.FILTER_PARAMS + " is not found in Query [" + queryString + "] if FILTERS is not EMPTY!!"); } /************************* * END VALIDATION ************************/ String finalQuery = queryString.trim(); List<Object> params = new ArrayList<Object>(); if (objectArray != null) { if (objectArray.length == 1 && objectArray[0] instanceof List) params = (List<Object>) objectArray[0]; else params = Arrays.asList(objectArray); } if (CollectionUtil.isNotEmpty(datagridModel.getFilters())) { for (Filter filter : datagridModel.getFilters()) { if (filter != null) throw new DataException("The Filter features still not implemented yet"); } } List<Object> countParams = new ArrayList<Object>(params); if (hasCountQueryString) countQuery = countQueryString; else { countQuery = "SELECT COUNT(" + alias + ") "; if (finalQuery.toUpperCase().startsWith("SELECT")) { int ind = finalQuery.toUpperCase().indexOf("FROM"); countQuery += finalQuery.substring(ind); } else { countQuery += finalQuery; } } if (!datagridModel.isDisableSort() && CollectionUtil.isNotEmpty(datagridModel.getSorters())) { if (StringUtils.contains(finalQuery.toUpperCase(), "ORDER BY")) { finalQuery += ", "; } else { finalQuery += " ORDER BY "; } for (Iterator<Sorter> iter = datagridModel.getSorters().iterator(); iter.hasNext();) { Sorter sorter = iter.next(); if (StringUtils.isNotBlank(datagridModel.getExtraMapping(sorter.getColumn()))) finalQuery += datagridModel.getExtraMapping(sorter.getColumn()) + " " + sorter.getDirection(); else finalQuery += alias + "." + sorter.getColumn() + " " + sorter.getDirection(); if (iter.hasNext()) { finalQuery += ", "; } } } // log.debug("countParams = " + countParams); // log.debug("countQuery = " + countQuery); // log.debug("params = " + params); // log.debug("finalQuery = " + finalQuery); List<T> result = (List<T>) findBlock(finalQuery, datagridModel.getRecordOffset(), datagridModel.getPageSize(), params.toArray()); datagridModel.setRecords(result); Long count = (Long) this.findUnique(countQuery, countParams.toArray()); datagridModel.setTotalRecords(count); } private QueryParams translateExampleToQueryParams(Object example, String... orderBy) { Object newObj = example; Entity entity = ((Entity) newObj.getClass().getAnnotation(Entity.class)); if (entity == null) throw new DataException(newObj.getClass().getSimpleName() + " class is not valid JPA annotated bean"); String entityName = StringUtils.isBlank(entity.name()) ? example.getClass().getSimpleName() : entity.name(); String aliasName = StringUtils.isBlank(entity.name()) ? "obj" : entity.name(); String hql = "SELECT " + aliasName + " FROM "; List<Object> params = new ArrayList<Object>(); BeanWrapper beanO1 = new BeanWrapperImpl(newObj); PropertyDescriptor[] proDescriptorsO1 = beanO1.getPropertyDescriptors(); int propertyLength = proDescriptorsO1.length; if (newObj != null) { hql += entityName + " " + aliasName; } if (example instanceof VoBase) { VoBase voBase = (VoBase) example; for (String key : voBase.getJoinTables().keySet()) { if (StringUtils.isNotBlank(key)) { hql += " JOIN " + key + " " + voBase.getJoinTables().get(key); } } } hql += " WHERE 1=1"; int paramCount = 0; for (int i = 0; i < propertyLength; i++) { try { Object propertyValueO1 = beanO1.getPropertyValue(proDescriptorsO1[i].getName()); if ((propertyValueO1 instanceof String && StringUtils.isNotBlank((String) propertyValueO1)) || propertyValueO1 instanceof Long || propertyValueO1 instanceof Double || propertyValueO1 instanceof Integer || propertyValueO1 instanceof Boolean || propertyValueO1 instanceof Date || propertyValueO1.getClass().isPrimitive()) { Field field = null; try { field = example.getClass().getDeclaredField(proDescriptorsO1[i].getName()); } catch (NoSuchFieldException e) { if (propertyValueO1 instanceof Boolean || propertyValueO1.getClass().isPrimitive()) { String fieldName = "is" + StringUtils.upperCase(proDescriptorsO1[i].getName().substring(0, 1)) + proDescriptorsO1[i].getName().substring(1); field = example.getClass().getDeclaredField(fieldName); } } if (proDescriptorsO1[i].getName() != null && field != null && !field.isAnnotationPresent(Transient.class)) { if (!Arrays.asList(VoBase.propertiesVer).contains(proDescriptorsO1[i].getName())) { hql += " AND " + aliasName + "." + field.getName() + " = ?" + (++paramCount); params.add(propertyValueO1); } } } else if (propertyValueO1 != null) { Field field = example.getClass().getDeclaredField(proDescriptorsO1[i].getName()); if (field.isAnnotationPresent(javax.persistence.Id.class) || field.isAnnotationPresent(javax.persistence.EmbeddedId.class)) { BeanWrapper bean = new BeanWrapperImpl(propertyValueO1); PropertyDescriptor[] proDescriptors = bean.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : proDescriptors) { Object propertyValueId = bean.getPropertyValue(propertyDescriptor.getName()); if (propertyValueId != null && ReflectionUtil.isJavaDataType(propertyValueId)) { hql += " AND " + aliasName + "." + proDescriptorsO1[i].getName() + "." + propertyDescriptor.getName() + " = ?" + (++paramCount); params.add(bean.getPropertyValue(propertyDescriptor.getName())); } } } } } catch (Exception e) { } } // not condition if (example instanceof VoBase) { VoBase voBase = (VoBase) example; for (String key : voBase.getNotConditions().keySet()) { if (StringUtils.isNotBlank(key)) { hql += " AND " + aliasName + "." + key + "!= ?" + (++paramCount); params.add(voBase.getNotConditions().get(key)); } } } // like condition if (example instanceof VoBase) { VoBase voBase = (VoBase) example; for (String key : voBase.getLikeConditions().keySet()) { if (StringUtils.isNotBlank(key)) { hql += " AND " + aliasName + "." + key + " LIKE ?" + (++paramCount); params.add(voBase.getLikeConditions().get(key)); } } } if (orderBy != null && orderBy.length != 0) { hql += " ORDER BY "; long count = 1; for (String orderByStr : orderBy) { if (count != 1) hql += ","; hql += aliasName + "." + orderByStr; count += 1; } } log.debug("hql = " + hql); return new QueryParams(hql, params); } public List<T> findByExample(T example, String... orderBy) { QueryParams queryParams = translateExampleToQueryParams(example, orderBy); return findQueryAsList(queryParams.query, queryParams.params.toArray()); } public List<T> findByExample(T example, List<String> orderBy) { return findByExample(example, orderBy.toArray(new String[0])); } public void refresh(T example) { em.refresh(example); } public void flush() { em.flush(); } public int bulkUpdate(String query, final Object... objectArray) { final String query2 = convertJpaPositionParams(query); Query q = em.createQuery(query2); for (int i = 0; i < objectArray.length; i++) { q.setParameter(i + 1, objectArray[i]); } return q.executeUpdate(); } /** * convert hibernate positional parameter to JPA positional parameter notation.</br> For example: convert * <code>select a from A a where a.id=? and a.status=?</code> to * <code>select a from A a where a.id=?1 and a.status=?2</code> * * @param query * @return */ public String convertJpaPositionParams(String query) { if (StringUtils.isBlank(query)) return query; // bypass if the query is using JPA positional parameter notation if (query.indexOf("?1") >= 0) { return query; } else if (query.indexOf("?") >= 0) { StringBuffer sb = new StringBuffer(); Pattern p = Pattern.compile(Pattern.quote("?"), Pattern.CASE_INSENSITIVE); Matcher matcher = p.matcher(query); boolean result = matcher.find(); int count = 0; while (result) { String g = matcher.group(); matcher.appendReplacement(sb, g + (++count)); result = matcher.find(); } matcher.appendTail(sb); log.debug("sb.toString() = " + sb.toString()); return sb.toString(); } return query; } private class QueryParams { private String query; private List<Object> params; public QueryParams(String query, List<Object> params) { this.query = query; this.params = params; } } public void setEntityManager(EntityManager em) { this.em = em; } protected List<?> exFindQueryAsList(String query, Object... objectArray) { return findQueryAsList(query, objectArray); } protected List<?> exFindQueryNameAsList(String queryName, Object... objectArray) { return findQueryNameAsList(queryName, objectArray); } protected Object exFindFirst(String query, Object... objectArray) { return findFirst(query, objectArray); } protected Object exFindUnique(final String queryString, final Object... objectArray) { return findUnique(queryString, objectArray); } @SuppressWarnings("unchecked") private List<T> find(final String queryString, final Object... values) { Query queryObject = em.createQuery(queryString); if (values != null) { for (int i = 0; i < values.length; i++) { queryObject.setParameter(i + 1, values[i]); } } return queryObject.getResultList(); } @SuppressWarnings("unchecked") private List<T> findByNamedQuery(final String queryName, final Object... values) throws DataAccessException { Query queryObject = em.createNamedQuery(queryName); if (values != null) { for (int i = 0; i < values.length; i++) { queryObject.setParameter(i + 1, values[i]); } } return queryObject.getResultList(); } }