org.kuali.rice.krad.dao.impl.PersistenceDaoJpa.java Source code

Java tutorial

Introduction

Here is the source code for org.kuali.rice.krad.dao.impl.PersistenceDaoJpa.java

Source

/**
 * Copyright 2005-2013 The Kuali Foundation
 *
 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
 *
 * 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.kuali.rice.krad.dao.impl;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import org.apache.commons.lang.StringUtils;
import org.hibernate.proxy.HibernateProxy;
import org.kuali.rice.core.framework.persistence.jpa.metadata.CollectionDescriptor;
import org.kuali.rice.core.framework.persistence.jpa.metadata.EntityDescriptor;
import org.kuali.rice.core.framework.persistence.jpa.metadata.JoinColumnDescriptor;
import org.kuali.rice.core.framework.persistence.jpa.metadata.MetadataManager;
import org.kuali.rice.core.framework.persistence.jpa.metadata.ObjectDescriptor;
import org.kuali.rice.krad.dao.PersistenceDao;
import org.kuali.rice.krad.service.KRADServiceLocator;

public class PersistenceDaoJpa implements PersistenceDao {
    static org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory
            .getLog(PersistenceDaoJpa.class);

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * @see org.kuali.rice.krad.dao.PersistenceDao#clearCache()
     */
    public void clearCache() {
    }

    /**
     * @see org.kuali.rice.krad.dao.PersistenceDao#resolveProxy(java.lang.Object)
     */
    public Object resolveProxy(Object o) {
        if (o instanceof HibernateProxy) {
            try {
                final Object realObject = ((HibernateProxy) o).getHibernateLazyInitializer().getImplementation();
                return realObject;
            } catch (EntityNotFoundException enfe) {
                return null;
            }
        }
        return o;
    }

    /**
     * @see org.kuali.rice.krad.dao.PersistenceDao#retrieveAllReferences(java.lang.Object)
     */
    public void retrieveAllReferences(Object o) {
        EntityDescriptor ed = MetadataManager.getEntityDescriptor(o.getClass());
        for (ObjectDescriptor od : ed.getObjectRelationships()) {
            retrieveReference(o, od.getAttributeName());
        }
        for (CollectionDescriptor cd : ed.getCollectionRelationships()) {
            retrieveReference(o, cd.getAttributeName());
        }
    }

    /**
     * @see org.kuali.rice.krad.dao.PersistenceDao#retrieveReference(java.lang.Object, java.lang.String)
     */
    public void retrieveReference(Object o, String referenceName) {
        try {
            if (getEntityManager().contains(o)) {
                LOG.debug("the entity manager contains the object");
            }

            Field field = getField(o.getClass(), referenceName);
            field.setAccessible(true);

            String fk = null;
            String foreignPK = null;

            if (isReferenceCollection(o, referenceName)) {
                Collection reference = retrieveCollectionReference(o, referenceName);
                field.set(o, reference);
            } else {
                Object reference = retrieveObjectReference(o, referenceName);
                field.set(o, reference);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Field getField(Class clazz, String name) throws NoSuchFieldException {
        if (clazz.equals(Object.class)) {
            throw new NoSuchFieldException(name);
        }
        Field field = null;
        try {
            field = clazz.getDeclaredField(name);
        } catch (Exception e) {
        }
        if (field == null) {
            field = getField(clazz.getSuperclass(), name);
        }
        return field;
    }

    /**
     * Determines if the reference on the given object represents a collection or not
     * 
     * @param o the object which is to be refreshed
     * @param referenceName the name of the reference to refresh
     * @return true if the reference is a collection, false otherwise
     */
    protected boolean isReferenceCollection(Object o, String referenceName) {
        EntityDescriptor ed = MetadataManager.getEntityDescriptor(o.getClass());
        return ed.getCollectionDescriptorByName(referenceName) != null;
    }

    /**
     * This method fetches a collection to refresh a reference
     * 
     * @param o the object to refresh
     * @param referenceName the name of the reference to refresh
     * @return the retrieved object to refresh the 
     * @throws NoSuchFieldException 
     * @throws IllegalAccessException 
     * @throws IllegalArgumentException 
     */
    protected Collection retrieveCollectionReference(Object o, String referenceName)
            throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        final EntityDescriptor ed = MetadataManager.getEntityDescriptor(o.getClass());
        final CollectionDescriptor cd = ed.getCollectionDescriptorByName(referenceName);
        final EntityDescriptor foreignEntityDescriptor = MetadataManager.getEntityDescriptor(cd.getTargetEntity());

        Map<String, Object> searchKey = new HashMap<String, Object>();
        for (String foreignKey : cd.getForeignKeyFields()) {
            Field localField = getField(o.getClass(), foreignKey);
            localField.setAccessible(true);
            final Object localValue = localField.get(o);

            final String foreignKeyProperty = getForeignKeyPropertyForKeyWithPossibleInverse(foreignKey, ed,
                    foreignEntityDescriptor, cd);

            searchKey.put(foreignKeyProperty, localValue);
        }
        return KRADServiceLocator.getBusinessObjectService().findMatching(cd.getTargetEntity(), searchKey);
    }

    /**
     * Finds the correct foreign key property which corresponds to the given key
     * 
     * @param foreignKey the name of the key we want to find the proper foreign name for
     * @param localEntityDescriptor the descriptor of the entity that key is on
     * @param foreignEntityDescriptor the descriptor of the entity we're trying to retrieve
     * @param joinColumnDescriptors a Map of the JoinColumnDescriptors that describe the relationship from the local entity's point of view, keyed by the column name of the JoinColumnDescriptor 
     * @return the name of the property on the related object
     */
    protected String getForeignKeyPropertyForKeyWithPossibleInverse(String foreignKey,
            EntityDescriptor localEntityDescriptor, EntityDescriptor foreignEntityDescriptor,
            CollectionDescriptor collectionDescriptor) {
        final String foreignKeyColumn = localEntityDescriptor.getFieldByName(foreignKey).getColumn();

        int count = 0;
        JoinColumnDescriptor joinColumnDescriptor = null;
        JoinColumnDescriptor inverseColumnDescriptor = null;
        while (count < collectionDescriptor.getJoinColumnDescriptors().size() && joinColumnDescriptor == null) {
            if (collectionDescriptor.getJoinColumnDescriptors().get(count).getName()
                    .equalsIgnoreCase(foreignKeyColumn)) {
                joinColumnDescriptor = collectionDescriptor.getJoinColumnDescriptors().get(count);
                if (count < collectionDescriptor.getInverseJoinColumnDescriptors().size()) {
                    inverseColumnDescriptor = collectionDescriptor.getInverseJoinColumnDescriptors().get(count);
                }
            }
            count += 1;
        }

        if (inverseColumnDescriptor != null) {
            return foreignEntityDescriptor.getFieldByColumnName(inverseColumnDescriptor.getName()).getName();
        }

        if (!StringUtils.isBlank(joinColumnDescriptor.getReferencedColumName())) {
            return foreignEntityDescriptor.getFieldByColumnName(joinColumnDescriptor.getReferencedColumName())
                    .getName();
        }

        return foreignEntityDescriptor.getFieldByColumnName(joinColumnDescriptor.getName()).getName();

    }

    /**
     * Fetches an object reference
     * 
     * @param o the object to refresh
     * @param referenceName the name of the reference to fetch
     * @return the fetched referred to object
     * @throws IllegalAccessException 
     * @throws IllegalArgumentException 
     * @throws NoSuchFieldException 
     * @throws ClassNotFoundException 
     * @throws InstantiationException 
     */
    protected Object retrieveObjectReference(Object o, String referenceName) throws IllegalArgumentException,
            IllegalAccessException, NoSuchFieldException, InstantiationException, ClassNotFoundException {
        final EntityDescriptor ed = MetadataManager.getEntityDescriptor(o.getClass());
        final ObjectDescriptor od = ed.getObjectDescriptorByName(referenceName);

        final Object foreignKeyObject = buildForeignKeyObject(o, ed, od);
        return getEntityManager().find(od.getTargetEntity(), foreignKeyObject);
    }

    /**
     * Builds a foreign key object for the relationship given by the foreignKeyClass and the objectDescriptor
     * 
     * @param o the object to refresh
     * @param localEntityDescriptor the entity descriptor for that object
     * @param objectDescriptor the object descriptor for the relationship to refresh
     * @return the foreign key to fetch that object
     * @throws IllegalArgumentException
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     * @throws InstantiationException 
     */
    protected Object buildForeignKeyObject(Object o, EntityDescriptor localEntityDescriptor,
            ObjectDescriptor objectDescriptor)
            throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        return (objectDescriptor.getForeignKeyFields().size() == 1)
                ? buildSingleKeyForeignKeyObject(o, objectDescriptor.getForeignKeyFields().get(0))
                : buildCompositeForeignKeyObject(o, localEntityDescriptor, objectDescriptor);
    }

    /**
     * Builds a composite key to fetch a reference
     * 
     * @param o the object to refresh
     * @param localEntityDescriptor the entity descriptor for that object
     * @param objectDescriptor the object descriptor for the relationship to refresh
     * @return the foreign key to fetch that object
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     */
    private Object buildCompositeForeignKeyObject(Object o, EntityDescriptor localEntityDescriptor,
            ObjectDescriptor objectDescriptor)
            throws InstantiationException, IllegalAccessException, NoSuchFieldException {
        final Map<String, JoinColumnDescriptor> joinColumnDescriptors = buildJoinColumnDescriptorMap(
                objectDescriptor.getJoinColumnDescriptors());

        final EntityDescriptor foreignEntityDescriptor = MetadataManager
                .getEntityDescriptor(objectDescriptor.getTargetEntity());
        final Class foreignEntityIdClass = foreignEntityDescriptor.getIdClass();

        Object foreignEntityId = foreignEntityIdClass.newInstance();
        for (String foreignKey : objectDescriptor.getForeignKeyFields()) {
            // get the value from the current object
            Field localField = getField(o.getClass(), foreignKey);
            localField.setAccessible(true);
            final Object localValue = localField.get(o);

            final String foreignKeyProperty = getForeignKeyPropertyForKey(foreignKey, localEntityDescriptor,
                    foreignEntityDescriptor, joinColumnDescriptors);

            Field foreignField = getField(foreignEntityId.getClass(), foreignKeyProperty);
            foreignField.setAccessible(true);
            foreignField.set(foreignEntityId, localValue);
        }
        return foreignEntityId;
    }

    /**
     * Finds the correct foreign key property which corresponds to the given key
     * 
     * @param foreignKey the name of the key we want to find the proper foreign name for
     * @param localEntityDescriptor the descriptor of the entity that key is on
     * @param foreignEntityDescriptor the descriptor of the entity we're trying to retrieve
     * @param joinColumnDescriptors a Map of the JoinColumnDescriptors that describe the relationship from the local entity's point of view, keyed by the column name of the JoinColumnDescriptor 
     * @return the name of the property on the related object
     */
    protected String getForeignKeyPropertyForKey(String foreignKey, EntityDescriptor localEntityDescriptor,
            EntityDescriptor foreignEntityDescriptor, Map<String, JoinColumnDescriptor> joinColumnDescriptors) {
        final String foreignKeyColumn = localEntityDescriptor.getFieldByName(foreignKey).getColumn();
        final JoinColumnDescriptor joinColumnDescriptor = joinColumnDescriptors.get(foreignKeyColumn);

        return (!StringUtils.isBlank(joinColumnDescriptor.getReferencedColumName()))
                ? foreignEntityDescriptor.getFieldByColumnName(joinColumnDescriptor.getReferencedColumName())
                        .getName()
                : foreignEntityDescriptor.getFieldByColumnName(joinColumnDescriptor.getName()).getName();

    }

    /**
     * Turns a List of JoinColumnDescriptors and maps them by their name
     * 
     * @param joinColumnDescriptors a List of JoinColumnDescriptors
     * @return a Map the List as a Map, keyed by the name of the JoinColumn
     */
    protected Map<String, JoinColumnDescriptor> buildJoinColumnDescriptorMap(
            List<JoinColumnDescriptor> joinColumnDescriptors) {
        Map<String, JoinColumnDescriptor> descriptorMap = new HashMap<String, JoinColumnDescriptor>();
        for (JoinColumnDescriptor joinColumnDescriptor : joinColumnDescriptors) {
            descriptorMap.put(joinColumnDescriptor.getName(), joinColumnDescriptor);
        }
        return descriptorMap;
    }

    /**
     * Builds a foreign key, where that foreign key has a single field
     * 
     * @param o the object to get the foreign key value from
     * @param singleForeignKeyFieldName the name of the foreign key field
     * @return a value for the foreign key
     * @throws NoSuchFieldException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    protected Object buildSingleKeyForeignKeyObject(Object o, String singleForeignKeyFieldName)
            throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        Field singleFKField = getField(o.getClass(), singleForeignKeyFieldName);
        singleFKField.setAccessible(true);
        return singleFKField.get(o);
    }

    /**
     * True if object is an instance of HibernateProxy, false otherwise
     * 
     * @see org.kuali.rice.krad.dao.PersistenceDao#isProxied(java.lang.Object)
     */
    public boolean isProxied(Object object) {
        return (object instanceof HibernateProxy);
    }

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

    /**
     * @param entityManager the entityManager to set
     */
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
}