org.agric.oxm.utils.JpaUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.agric.oxm.utils.JpaUtils.java

Source

/*
 * Copyright 2009-2011 the original author or authors.
 *
 * 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 org.agric.oxm.utils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Fetch;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

import org.apache.commons.lang.StringUtils;

/**
 * Utility class for dealing with JPA API
 * 
 * @author Jose Luis Martin
 * @since 1.1
 */
public abstract class JpaUtils {

    private static String ALIAS_PATTERN_STRING = "(?<=from)\\s+(?:\\S+)\\s+(?:as\\s+)*(\\w*)";
    private static Pattern ALIAS_PATTERN = Pattern.compile(ALIAS_PATTERN_STRING, Pattern.CASE_INSENSITIVE);
    private static String FROM_PATTERN_STRING = "(from.*+)";
    private static Pattern FROM_PATTERN = Pattern.compile(FROM_PATTERN_STRING, Pattern.CASE_INSENSITIVE);
    private static volatile long aliasCount = 0;

    /**
     * Result count from a CriteriaQuery
     * 
     * @param em
     *            Entity Manager
     * @param criteria
     *            Criteria Query to count results
     * @return row count
     */
    public static <T> Long count(EntityManager em, CriteriaQuery<T> criteria) {

        return em.createQuery(countCriteria(em, criteria)).getSingleResult();
    }

    /**
     * Create a row count CriteriaQuery from a CriteriaQuery
     * 
     * @param em
     *            entity manager
     * @param criteria
     *            source criteria
     * @return row coutnt CriteriaQuery
     */
    public static <T> CriteriaQuery<Long> countCriteria(EntityManager em, CriteriaQuery<T> criteria) {
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
        copyCriteriaNoSelection(criteria, countCriteria);
        countCriteria.select(builder.count(findRoot(countCriteria, criteria.getResultType())));

        return countCriteria;
    }

    /**
     * Gets The result alias, if none set a default one and return it
     * 
     * @param selection
     * @return root alias or generated one
     */
    public static synchronized <T> String getOrCreateAlias(Selection<T> selection) {
        // reset alias count
        if (aliasCount > 1000)
            aliasCount = 0;

        String alias = selection.getAlias();
        if (alias == null) {
            alias = "JDAL_generatedAlias" + aliasCount++;
            selection.alias(alias);
        }
        return alias;

    }

    /**
     * Find Root of result type
     * 
     * @param query
     *            criteria query
     * @return the root of result type or null if none
     */
    public static <T> Root<T> findRoot(CriteriaQuery<T> query) {
        return findRoot(query, query.getResultType());
    }

    /**
     * Find the Root with type class on CriteriaQuery Root Set
     * 
     * @param <T>
     *            root type
     * @param query
     *            criteria query
     * @param clazz
     *            root type
     * @return Root<T> of null if none
     */
    public static <T> Root<T> findRoot(CriteriaQuery<?> query, Class<T> clazz) {

        for (Root<?> r : query.getRoots()) {
            if (clazz.equals(r.getJavaType())) {
                return (Root<T>) r.as(clazz);
            }
        }
        return null;
    }

    /**
     * Find Joined Root of type clazz
     * 
     * @param <T>
     * @param query
     *            the criteria query
     * @param rootClass
     *            the root class
     * @param joinClass
     *            the join class
     * @return the Join
     */
    @SuppressWarnings("unchecked")
    public static <T, K> Join<T, K> findJoinedType(CriteriaQuery<T> query, Class<T> rootClass, Class<K> joinClass) {
        Root<T> root = findRoot(query, rootClass);
        Join<T, K> join = null;
        for (Join<T, ?> j : root.getJoins()) {
            if (j.getJoinType().equals(joinClass)) {
                join = (Join<T, K>) j;
            }
        }
        return join;
    }

    /**
     * Gets a Path from Path using property path
     * 
     * @param path
     *            the base path
     * @param propertyPath
     *            property path String like "customer.order.price"
     * @return a new Path for property
     */
    public static Path<?> getPath(Path<?> path, String propertyPath) {
        if (StringUtils.isEmpty(propertyPath))
            return path;

        String name = StringUtils.substringBefore(propertyPath, PropertyUtils.PROPERTY_SEPARATOR);
        Path<?> p = path.get(name);

        return getPath(p, StringUtils.substringAfter(propertyPath, PropertyUtils.PROPERTY_SEPARATOR));

    }

    /**
     * Create a count query string from a query string
     * 
     * @param queryString
     *            string to parse
     * @return the count query string
     */
    public static String createCountQueryString(String queryString) {
        return queryString.replaceFirst("^.*(?i)from", "select count (*) from ");
    }

    /**
     * Gets the alias of root entity of JQL query
     * 
     * @param queryString
     *            JQL query
     * @return alias of root entity.
     */
    public static String getAlias(String queryString) {
        Matcher m = ALIAS_PATTERN.matcher(queryString);
        return m.find() ? m.group(1) : null;
    }

    /**
     * Add order by clause to queryString
     * 
     * @param queryString
     *            JPL Query String
     * @param propertyPath
     *            Order properti
     * @param asc
     *            true if ascending
     * @return JQL Query String with Order clause appened.
     */
    public static String addOrder(String queryString, String propertyPath, boolean asc) {

        if (StringUtils.containsIgnoreCase(queryString, "order by")) {
            return queryString;
        }

        StringBuilder sb = new StringBuilder(queryString);
        sb.append(" ORDER BY ");
        sb.append(getAlias(queryString));
        sb.append(".");
        sb.append(propertyPath);
        sb.append(" ");
        sb.append(asc ? "ASC" : "DESC");

        return sb.toString();
    }

    /**
     * Gets Query String for selecting primary keys
     * 
     * @param queryString
     *            the original query
     * @param name
     *            primary key name
     * @return query string
     */
    public static String getKeyQuery(String queryString, String name) {
        Matcher m = FROM_PATTERN.matcher(queryString);
        if (m.find()) {
            StringBuilder sb = new StringBuilder("SELECT ");
            sb.append(getAlias(queryString));
            sb.append(".");
            sb.append(name);
            sb.append(" ");
            sb.append(m.group());
            return sb.toString();
        }

        return null;
    }

    /**
     * Copy Criteria without Selection
     * 
     * @param from
     *            source Criteria
     * @param to
     *            destination Criteria
     */
    public static void copyCriteriaNoSelection(CriteriaQuery<?> from, CriteriaQuery<?> to) {

        // Copy Roots
        for (Root<?> root : from.getRoots()) {
            Root<?> dest = to.from(root.getJavaType());
            dest.alias(getOrCreateAlias(root));
            copyJoins(root, dest);
        }

        to.groupBy(from.getGroupList());
        to.distinct(from.isDistinct());
        to.having(from.getGroupRestriction());
        to.where(from.getRestriction());
        to.orderBy(from.getOrderList());
    }

    public static <T> void copyCriteria(CriteriaQuery<T> from, CriteriaQuery<T> to) {
        copyCriteriaNoSelection(from, to);
        to.select(from.getSelection());
    }

    /**
     * Copy Joins
     * 
     * @param from
     *            source Join
     * @param to
     *            destination Join
     */
    public static void copyJoins(From<?, ?> from, From<?, ?> to) {
        for (Join<?, ?> j : from.getJoins()) {
            Join<?, ?> toJoin = to.join(j.getAttribute().getName(), j.getJoinType());
            toJoin.alias(getOrCreateAlias(j));

            copyJoins(j, toJoin);
        }

        for (Fetch<?, ?> f : from.getFetches()) {
            Fetch<?, ?> toFetch = to.fetch(f.getAttribute().getName());
            copyFetches(f, toFetch);

        }
    }

    /**
     * Copy Fetches
     * 
     * @param from
     *            source Fetch
     * @param to
     *            dest Fetch
     */
    public static void copyFetches(Fetch<?, ?> from, Fetch<?, ?> to) {
        for (Fetch<?, ?> f : from.getFetches()) {
            Fetch<?, ?> toFetch = to.fetch(f.getAttribute().getName());
            // recursively copy fetches
            copyFetches(f, toFetch);
        }
    }
}