com.impetus.ankush.common.dao.impl.GenericDaoJpa.java Source code

Java tutorial

Introduction

Here is the source code for com.impetus.ankush.common.dao.impl.GenericDaoJpa.java

Source

/*******************************************************************************
 * ===========================================================
 * Ankush : Big Data Cluster Management Solution
 * ===========================================================
 * 
 * (C) Copyright 2014, by Impetus Technologies
 * 
 * This is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (LGPL v3) as
 * published by the Free Software Foundation;
 * 
 * This software is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this software; if not, write to the Free Software Foundation, 
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ******************************************************************************/
package com.impetus.ankush.common.dao.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.impetus.ankush.common.dao.GenericDao;

/**
 * This class serves as the Base class for all other DAOs - namely to hold
 * common CRUD methods that they might all use. You should only need to extend
 * this class when your require custom CRUD logic.
 * 
 * To register this class in your Spring context file, use the following XML.
 * 
 * @param <T>
 *            a type variable
 * @param <P>
 *            the primary key for that type
 */
public class GenericDaoJpa<T, P extends Serializable> implements GenericDao<T, P> {

    /** The Constant UNCHECKED. */
    private static final String UNCHECKED = "unchecked";

    /** The Constant SELECT_OBJ_FROM. */
    private static final String SELECT_OBJ_FROM = "select obj from ";

    /**
     * Log variable for all child classes. Uses LogFactory.getLog(getClass())
     * from Commons Logging
     */
    protected final Logger log = LoggerFactory.getLogger(getClass());

    /**
     * Entity manager, injected by Spring using @PersistenceContext annotation
     * on setEntityManager().
     */
    @PersistenceContext
    private EntityManager entityManager;

    /** The persistent class. */
    private final Class<T> persistentClass;

    /**
     * Constructor that takes in a class to see which type of entity to persist.
     * Use this constructor when subclassing or using dependency injection.
     * 
     * @param persistentClass
     *            the class type you'd like to persist
     */
    public GenericDaoJpa(final Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    /**
     * Constructor that takes in a class to see which type of entity to persist.
     * Use this constructor when subclassing or using dependency injection.
     * 
     * @param persistentClass
     *            the class type you'd like to persist
     * @param entityManager
     *            the configured EntityManager for JPA implementation.
     */
    public GenericDaoJpa(final Class<T> persistentClass, EntityManager entityManager) {
        this.persistentClass = persistentClass;
        this.entityManager = entityManager;
    }

    /**
     * Gets the entity manager.
     * 
     * @return the entity manager
     */
    public EntityManager getEntityManager() {
        return this.entityManager;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.ankush.common.dao.GenericDao#getAll(int, int,
     * java.lang.String[])
     */
    public List<T> getAll(int start, int maxResults, String... orderBy) {
        Query query = this.entityManager.createQuery(getAllQueryString() + createOrderByClause(orderBy));

        query.setFirstResult(start);
        query.setMaxResults(maxResults);

        return query.getResultList();
    }

    /**
     * Gets the all query string.
     * 
     * @return the all query string
     */
    private String getAllQueryString() {
        return SELECT_OBJ_FROM + this.persistentClass.getName() + " obj";
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.ankush.common.dao.GenericDao#getAllCount()
     */
    public int getAllCount() {
        return getCount(convertToCountQuery(getAllQueryString()), (List<Object>) null);
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings(UNCHECKED)
    public List<T> getAllDistinct() {
        return new ArrayList(new LinkedHashSet(getAll(0, Integer.MAX_VALUE)));
    }

    /**
     * {@inheritDoc}
     */
    public T get(P id) {
        T entity = this.entityManager.find(this.persistentClass, id);

        if (entity == null) {
            String msg = "Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...";
            log.warn(msg);
            throw new EntityNotFoundException(msg);
        }
        return entity;
    }

    /**
     * {@inheritDoc}
     */
    public T getGuarded(P id) {
        return this.entityManager.find(this.persistentClass, id);
    }

    /**
     * {@inheritDoc}
     */
    public T getReference(P id) {
        try {
            T entity = this.entityManager.getReference(this.persistentClass, id);
            if (entity == null) {
                throw new RuntimeException();
            }
            return entity;
        } catch (Exception e) {
            String msg = "Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...";
            log.warn(msg);
            throw new EntityNotFoundException(msg);
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean exists(P id) {
        T entity = this.entityManager.find(this.persistentClass, id);
        return entity != null;
    }

    /**
     * {@inheritDoc}
     */
    public T save(T object) {
        return this.entityManager.merge(object);
    }

    /**
     * {@inheritDoc}
     */
    public void remove(P id) {
        this.entityManager.remove(this.get(id));
    }

    /**
     * {@inheritDoc}
     */
    @SuppressWarnings(UNCHECKED)
    public T getByPropertyValue(Map<String, Object> propertyValueMap) {
        return (T) createSelectQuery(propertyValueMap).getSingleResult();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.ankush.common.dao.GenericDao#getAllByPropertyValue(java.util
     * .Map, int, int, java.lang.String[])
     */
    @SuppressWarnings(UNCHECKED)
    public List<T> getAllByPropertyValue(Map<String, Object> propertyValueMap, int start, int maxResults,
            String... orderBy) {
        Query query = createSelectQuery(propertyValueMap, orderBy);
        query.setFirstResult(start);
        query.setMaxResults(maxResults);
        return query.getResultList();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.ankush.common.dao.GenericDao#getAllByPropertyValueCount(java
     * .util.Map)
     */
    public int getAllByPropertyValueCount(Map<String, Object> propertyValueMap) {
        LinkedHashMap<String, Object> orderedMap = getOrderedMap(propertyValueMap);
        String selectQueryString = createSelectQueryString(orderedMap).toString();
        return this.getCount(convertToCountQuery(selectQueryString), orderedMap);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.ankush.common.dao.GenericDao#getAllByNativeQuery(java.lang
     * .String)
     */
    public List<T> getAllByNativeQuery(String sql) {
        return entityManager.createNativeQuery(sql, persistentClass).getResultList();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.ankush.common.dao.GenericDao#executeNativeQuery(java.lang
     * .String)
     */
    public int executeNativeQuery(String sql) {
        return entityManager.createNativeQuery(sql, persistentClass).executeUpdate();
    }

    /**
     * {@inheritDoc}
     */
    public int deleteAllByPropertyValue(Map<String, Object> propertyValueMap) {
        List<T> objects = getAllByPropertyValue(propertyValueMap, 0, Integer.MAX_VALUE);
        this.removeAll(objects);
        this.entityManager.flush();
        return objects.size();
    }

    /**
     * Create a select query from the given property value map.
     * 
     * @param propertyValueMap
     *            query key value
     * @param orderBy
     *            the order by
     * @return Query object
     */
    private Query createSelectQuery(Map<String, Object> propertyValueMap, String... orderBy) {
        LinkedHashMap<String, Object> orderedMap = this.getOrderedMap(propertyValueMap);

        StringBuilder builder = createSelectQueryString(orderedMap).append(this.createOrderByClause(orderBy));

        Query query = this.entityManager.createQuery(builder.toString());

        // fill parameters
        this.assignQueryParameters(query, this.flattenParameterList(Collections.singletonList(orderedMap)));

        return query;
    }

    /**
     * Creates the select query string.
     * 
     * @param orderedMap
     *            the ordered map
     * @return the string builder
     */
    private StringBuilder createSelectQueryString(LinkedHashMap<String, Object> orderedMap) {
        return new StringBuilder(SELECT_OBJ_FROM).append(this.persistentClass.getName()).append(" obj where ")
                .append(this.createAndClause(orderedMap, 1));
    }

    /**
     * Removes the all.
     * 
     * @param objects
     *            the objects
     */
    private void removeAll(List<T> objects) {
        for (Object o : objects) {
            entityManager.remove(o);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.ankush.common.dao.GenericDao#getAllByNamedQuery(java.lang
     * .String, java.util.Map, int, int)
     */
    @SuppressWarnings(UNCHECKED)
    public List<T> getAllByNamedQuery(String queryName, Map<String, Object> propertyValueMap, int start,
            int maxResults) {
        Query query = getEntityManager().createNamedQuery(queryName);
        for (Entry<String, Object> entry : propertyValueMap.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        query.setFirstResult(start);
        query.setMaxResults(maxResults);
        return query.getResultList();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.ankush.common.dao.GenericDao#getAllOfOrMatch(java.util.Map,
     * int, int, java.lang.String[])
     */
    @SuppressWarnings(UNCHECKED)
    public List<T> getAllOfOrMatch(Map<String, Object> queryMap, int start, int maxResults, String... orderBy) {
        LinkedHashMap<String, Object> orderedMap = this.getOrderedMap(queryMap);

        StringBuilder builder = createSelectOrQueryString(orderedMap).append(this.createOrderByClause(orderBy));

        Query query = this.entityManager.createQuery(builder.toString());

        // fill parameters
        this.assignQueryParameters(query, this.flattenParameterList(Collections.singletonList(orderedMap)));
        query.setFirstResult(start);
        query.setMaxResults(maxResults);

        return query.getResultList();
    }

    /**
     * Creates the select or query string.
     * 
     * @param orderedMap
     *            the ordered map
     * @return the string builder
     */
    private StringBuilder createSelectOrQueryString(LinkedHashMap<String, Object> orderedMap) {
        return new StringBuilder(SELECT_OBJ_FROM).append(this.persistentClass.getName()).append(" obj where ")
                .append(this.createOrClause(orderedMap, 1));
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.ankush.common.dao.GenericDao#getAllOfOrMatchCount(java.util
     * .Map)
     */
    public int getAllOfOrMatchCount(Map<String, Object> queryMap) {

        LinkedHashMap<String, Object> orderedMap = getOrderedMap(queryMap);

        return getCount(convertToCountQuery(createSelectOrQueryString(orderedMap).toString()), orderedMap);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.ankush.common.dao.GenericDao#getAllByDisjunctionveNormalQuery
     * (java.util.List, int, int, java.lang.String[])
     */
    @SuppressWarnings(UNCHECKED)
    public List<T> getAllByDisjunctionveNormalQuery(List<Map<String, Object>> disjunctionMaps, int start,
            int maxResults, String... orderBy) {

        List<LinkedHashMap<String, Object>> orderedMaps = this.getOrderedMap(disjunctionMaps);

        StringBuilder builder = createDisjunctionNormalQueryString(orderedMaps)
                .append(this.createOrderByClause(orderBy));

        Query query = this.entityManager.createQuery(builder.toString());

        // fill parameters
        this.assignQueryParameters(query, this.flattenParameterList(orderedMaps));
        query.setFirstResult(start);
        query.setMaxResults(maxResults);

        return query.getResultList();
    }

    /**
     * Creates the disjunction normal query string.
     * 
     * @param orderedMaps
     *            the ordered maps
     * @return the string builder
     */
    private StringBuilder createDisjunctionNormalQueryString(List<LinkedHashMap<String, Object>> orderedMaps) {
        List<String> andClauses = new ArrayList<String>(orderedMaps.size());
        int startIndex = 1;
        for (LinkedHashMap<String, Object> queryMap : orderedMaps) {
            andClauses.add(this.createAndClause(queryMap, startIndex));
            startIndex += queryMap.size();
        }
        String disjunction = new StringBuilder("(").append(StringUtils.join(andClauses, ") or (")).append(") ")
                .toString();

        StringBuilder builder = new StringBuilder(SELECT_OBJ_FROM).append(this.persistentClass.getName())
                .append(" obj where ").append(disjunction);
        return builder;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.ankush.common.dao.GenericDao#
     * getAllByDisjunctionveNormalQueryCount(java.util.List)
     */
    public int getAllByDisjunctionveNormalQueryCount(List<Map<String, Object>> disjunctionMaps) {
        List<LinkedHashMap<String, Object>> orderedDisjunctionMaps = this.getOrderedMap(disjunctionMaps);
        return getCount(convertToCountQuery(createDisjunctionNormalQueryString(orderedDisjunctionMaps).toString()),
                this.flattenParameterList(orderedDisjunctionMaps));
    }

    /**
     * Gets the ordered map.
     * 
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param maps
     *            the maps
     * @return the ordered map
     */
    private <K, V> List<LinkedHashMap<K, V>> getOrderedMap(List<Map<K, V>> maps) {
        List<LinkedHashMap<K, V>> orderedMaps = new ArrayList<LinkedHashMap<K, V>>(maps.size());
        for (Map<K, V> map : maps) {
            orderedMaps.add(this.getOrderedMap(map));
        }
        return orderedMaps;
    }

    /**
     * Gets the ordered map.
     * 
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return the ordered map
     */
    private <K, V> LinkedHashMap<K, V> getOrderedMap(Map<K, V> map) {
        return new LinkedHashMap<K, V>(map);
    }

    /**
     * Flatten parameter list.
     * 
     * @param parameterMaps
     *            the parameter maps
     * @return the list
     */
    private List<Object> flattenParameterList(List<LinkedHashMap<String, Object>> parameterMaps) {
        List<Object> parameterList = new ArrayList<Object>();
        for (HashMap<String, Object> parameterMap : parameterMaps) {
            for (Entry<String, Object> entry : parameterMap.entrySet()) {
                parameterList.add(entry.getValue());
            }
        }
        return parameterList;
    }

    /**
     * Assign query parameters.
     * 
     * @param query
     *            the query
     * @param parameters
     *            the parameters
     */
    private void assignQueryParameters(Query query, List<Object> parameters) {
        for (int i = 0; i < parameters.size(); i++) {
            query.setParameter(i + 1, parameters.get(i));
        }
    }

    /**
     * Creates the and clause.
     * 
     * @param queryMap
     *            the query map
     * @param startIndex
     *            the start index
     * @return the string
     */
    private String createAndClause(LinkedHashMap<String, Object> queryMap, int startIndex) {
        return createClauseList(queryMap, startIndex, " and ");
    }

    /**
     * Creates the or clause.
     * 
     * @param queryMap
     *            the query map
     * @param startIndex
     *            the start index
     * @return the string
     */
    private String createOrClause(LinkedHashMap<String, Object> queryMap, int startIndex) {
        return createClauseList(queryMap, startIndex, " or ");
    }

    /**
     * Creates the clause list.
     * 
     * @param queryMap
     *            the query map
     * @param startIndex
     *            the start index
     * @param joiner
     *            the joiner
     * @return the string
     */
    private String createClauseList(LinkedHashMap<String, Object> queryMap, int startIndex, String joiner) {
        List<StringBuilder> clauses = new ArrayList<StringBuilder>(queryMap.size());

        for (String property : queryMap.keySet()) {
            clauses.add(new StringBuilder("obj.").append(property).append(" = ?").append(startIndex++));
        }
        return StringUtils.join(clauses, joiner);
    }

    /**
     * Creates the order by clause.
     * 
     * @param orderBy
     *            the order by
     * @return the string
     */
    private String createOrderByClause(String[] orderBy) {
        if (orderBy == null || orderBy.length == 0) {
            return StringUtils.EMPTY;
        }
        List<StringBuilder> clauses = new ArrayList<StringBuilder>(orderBy.length);
        for (String order : orderBy) {
            StringBuilder builder = new StringBuilder("obj.");
            if (order.charAt(0) == '-') {
                builder.append(order.substring(1)).append(" DESC");
            } else {
                builder.append(order);
            }
            clauses.add(builder);
        }
        return " order by " + StringUtils.join(clauses, ',');
    }

    /**
     * Convert to count query.
     * 
     * @param query
     *            the query
     * @return the string
     */
    private String convertToCountQuery(String query) {
        Pattern pattern = Pattern.compile("select(.+)from");
        Matcher matcher = pattern.matcher(query);
        if (matcher.find()) {
            String s = matcher.group(1).trim();
            query = StringUtils.replaceOnce(query, s, "count(" + s + ")");
        }
        return query;
    }

    /**
     * Gets the count.
     * 
     * @param queryString
     *            the query string
     * @param orderedMap
     *            the ordered map
     * @return the count
     */
    private int getCount(String queryString, LinkedHashMap<String, Object> orderedMap) {
        Query query = this.entityManager.createQuery(queryString);
        if (orderedMap != null) {
            assignQueryParameters(query, flattenParameterList(Collections.singletonList(orderedMap)));
        }
        return ((Long) query.getSingleResult()).intValue();
    }

    /**
     * Gets the count.
     * 
     * @param queryString
     *            the query string
     * @param parameterList
     *            the parameter list
     * @return the count
     */
    private int getCount(String queryString, List<Object> parameterList) {
        Query query = this.entityManager.createQuery(queryString);
        if (parameterList != null) {
            assignQueryParameters(query, parameterList);
        }
        return ((Long) query.getSingleResult()).intValue();
    }

    public List getCustomQuery(String queryString) {
        Query query = this.entityManager.createQuery(queryString);
        return query.getResultList();
    }
}