net.kamhon.ieagle.dao.Jpa2Dao.java Source code

Java tutorial

Introduction

Here is the source code for net.kamhon.ieagle.dao.Jpa2Dao.java

Source

/*
 * 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();
    }
}