All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.impetus.kundera.persistence.AbstractEntityReader Maven / Gradle / Ivy

There is a newer version: 2.9
Show newest version
/*******************************************************************************
 * * Copyright 2012 Impetus Infotech.
 *  *
 *  * 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 com.impetus.kundera.persistence;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.FetchType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.impetus.kundera.client.Client;
import com.impetus.kundera.client.ClientBase;
import com.impetus.kundera.client.EnhanceEntity;
import com.impetus.kundera.metadata.KunderaMetadataManager;
import com.impetus.kundera.metadata.MetadataUtils;
import com.impetus.kundera.metadata.model.EntityMetadata;
import com.impetus.kundera.metadata.model.Relation;
import com.impetus.kundera.metadata.model.Relation.ForeignKey;
import com.impetus.kundera.persistence.context.PersistenceCacheManager;
import com.impetus.kundera.property.PropertyAccessException;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.proxy.ProxyHelper;
import com.impetus.kundera.utils.KunderaCoreUtils;

/**
 * The Class AbstractEntityReader.
 * 
 * @author vivek.mishra
 */
public class AbstractEntityReader
{

    /** The log. */
    private static Logger log = LoggerFactory.getLogger(AbstractEntityReader.class);

    /** The lucene query from jpa query. */
    protected String luceneQueryFromJPAQuery;

    private AssociationBuilder associationBuilder;

    /**
     * Retrieves an entity from ID
     * 
     * @param primaryKey
     * @param m
     * @param client
     * @return
     */
    protected EnhanceEntity findById(Object primaryKey, EntityMetadata m, Client client)
    {
        try
        {
            Object o = client.find(m.getEntityClazz(), primaryKey);

            if (o == null)
            {
                // No entity found
                return null;
            }
            else
            {
                return o instanceof EnhanceEntity ? (EnhanceEntity) o : new EnhanceEntity(o, getId(o, m), null);
            }
        }
        catch (Exception e)
        {
            throw new EntityReaderException(e);
        }
    }

    /**
     * Recursively fetches associated entities for a given entity
     * 
     * @param entity
     * @param relationsMap
     * @param client
     * @param m
     * @param pd
     * @return
     */
    private Object handleAssociation(final Object entity, final Map relationsMap,
            final EntityMetadata m, final PersistenceDelegator pd, boolean lazilyloaded)
    {

        for (Relation relation : m.getRelations())
        {
            ForeignKey relationType = relation.getType();

            Object relationalObject = PropertyAccessorHelper.getObject(entity, relation.getProperty());

            if (KunderaCoreUtils.isEmptyOrNull(relationalObject) || ProxyHelper.isProxyOrCollection(relationalObject))
            {
                onRelation(entity, relationsMap, m, pd, relation, relationType, lazilyloaded);
            }
        }
        return entity;
    }

    /**
     * Parse over each relation of fetched entity.
     * 
     * @param entity
     * @param relationsMap
     * @param m
     * @param pd
     * @param relation
     * @param relationType
     * @param lazilyloaded
     */
    private void onRelation(final Object entity, final Map relationsMap, final EntityMetadata m,
            final PersistenceDelegator pd, Relation relation, ForeignKey relationType, boolean lazilyloaded)
    {

        FetchType fetchType = relation.getFetchType();

        if (!lazilyloaded && fetchType.equals(FetchType.LAZY))
        {
            final Object entityId = PropertyAccessorHelper.getId(entity, m);
            getAssociationBuilder().setProxyRelationObject(entity, relationsMap, m, pd, entityId, relation);
        }
        else
        {
            if (relation.getType().equals(ForeignKey.MANY_TO_MANY))
            {
                // First, Save this entity to persistence cache
                Field f = relation.getProperty();
                Object object = PropertyAccessorHelper.getObject(entity, f);
                final Object entityId = PropertyAccessorHelper.getId(entity, m);
                PersistenceCacheManager.addEntityToPersistenceCache(entity, pd, entityId);
                getAssociationBuilder().populateRelationForM2M(entity, m, pd, relation, object, relationsMap);
            }
            else
            {
                onRelation(entity, relationsMap, relation, m, pd, lazilyloaded);
            }
        }
    }

    /**
     * Method to handle one to one association relation events.
     * 
     * @param entity
     *            relation owning entity.
     * @param entityId
     *            entity id of relation owning entity.
     * @param relationsMap
     *            contains relation name and it's value.
     * @param m
     *            entity metadata.
     */
    private void onRelation(Object entity, Map relationsMap, final Relation relation,
            final EntityMetadata metadata, final PersistenceDelegator pd, boolean lazilyloaded)
    {
        final Object entityId = PropertyAccessorHelper.getId(entity, metadata);

        // if relation map contains value, then invoke target entity with find
        // by id.
        // else invoke target entity for find by relation, pass it's entityId as
        // a column value and relation.getJoinColumnName as column name.

        Object relationValue = relationsMap != null ? relationsMap.get(relation.getJoinColumnName()) : null;
        EntityMetadata targetEntityMetadata = KunderaMetadataManager.getEntityMetadata(relation.getTargetEntity());

        List relationalEntities = fetchRelations(relation, metadata, pd, entityId, relationValue, targetEntityMetadata);

        // parse for associated relation.

        if (relationalEntities != null)
        {
            for (Object relationEntity : relationalEntities)
            {
                if (relationEntity != null)
                {
                    onParseRelation(entity, pd, targetEntityMetadata, relationEntity, relation, lazilyloaded);
                    PersistenceCacheManager.addEntityToPersistenceCache(getEntity(relationEntity), pd,
                            PropertyAccessorHelper.getId(relationEntity, targetEntityMetadata));
                }
            }
        }

    }

    /**
     * Invokes parseRelations for relation entity and set relational entity
     * within entity
     * 
     * @param entity
     * @param pd
     * @param targetEntityMetadata
     * @param relationEntity
     * @param relation
     * @param lazilyloaded
     */
    private void onParseRelation(Object entity, final PersistenceDelegator pd, EntityMetadata targetEntityMetadata,
            Object relationEntity, Relation relation, boolean lazilyloaded)
    {
        parseRelations(entity, getEntity(relationEntity), getPersistedRelations(relationEntity), pd,
                targetEntityMetadata, lazilyloaded);

        // if relation ship is unary, no problem else we need to add
        setRelationToEntity(entity, relationEntity, relation);
    }

    /**
     * After successfully parsing set relational entity object within entity
     * object.
     * 
     * @param entity
     * @param relationEntity
     * @param relation
     */
    private void setRelationToEntity(Object entity, Object relationEntity, Relation relation)
    {
        if (relation.getTargetEntity().isAssignableFrom(getEntity(relationEntity).getClass()))
        {

            if (relation.isUnary())
            {
                PropertyAccessorHelper.set(entity, relation.getProperty(), getEntity(relationEntity));
            }
            else
            {
                Object associationObject = PropertyAccessorHelper.getObject(entity, relation.getProperty());
                if (associationObject == null || ProxyHelper.isProxyOrCollection(associationObject))
                {
                    associationObject = PropertyAccessorHelper.getCollectionInstance(relation.getProperty());
                    PropertyAccessorHelper.set(entity, relation.getProperty(), associationObject);
                }

                ((Collection) associationObject).add(getEntity(relationEntity));
            }
        }
    }

    /**
     * Parse relations of provided relationEntity.
     * 
     * @param originalEntity
     * @param relationEntity
     * @param relationsMap
     * @param pd
     * @param metadata
     * @param lazilyloaded
     */
    private void parseRelations(final Object originalEntity, final Object relationEntity,
            final Map relationsMap, final PersistenceDelegator pd, final EntityMetadata metadata,
            boolean lazilyloaded)
    {

        for (Relation relation : metadata.getRelations())
        {

            FetchType fetchType = relation.getFetchType();

            if (!lazilyloaded && fetchType.equals(FetchType.LAZY))
            {
                final Object entityId = PropertyAccessorHelper.getId(relationEntity, metadata);
                getAssociationBuilder().setProxyRelationObject(relationEntity, relationsMap, metadata, pd, entityId,
                        relation);
            }
            else
            {

                if (relation.isUnary() && relation.getTargetEntity().isAssignableFrom(originalEntity.getClass()))
                {
                    Object associationObject = PropertyAccessorHelper.getObject(relationEntity, relation.getProperty());
                    if (relation.getType().equals(ForeignKey.ONE_TO_ONE))
                    {
                        if ((associationObject == null || ProxyHelper.isProxyOrCollection(associationObject)))
                        {
                            PropertyAccessorHelper.set(relationEntity, relation.getProperty(), originalEntity);
                        }
                    }
                    else if (relationsMap != null && relationsMap.containsKey(relation.getJoinColumnName()))
                    {
                        PropertyAccessorHelper.set(relationEntity, relation.getProperty(), originalEntity);
                    }
                }
                else
                {
                    // Here
                    // onRelation(relationEntity, relationsMap, metadata, pd,
                    // relation, relationType);
                    final Object entityId = PropertyAccessorHelper.getId(relationEntity, metadata);
                    Object relationValue = relationsMap != null ? relationsMap.get(relation.getJoinColumnName()) : null;
                    final EntityMetadata targetEntityMetadata = KunderaMetadataManager.getEntityMetadata(relation
                            .getTargetEntity());
                    List immediateRelations = fetchRelations(relation, metadata, pd, entityId, relationValue,
                            targetEntityMetadata);
                    // Here in case of one-to-many/many-to-one we should skip
                    // this
                    // relation as it
                    if (immediateRelations != null && !immediateRelations.isEmpty())
                    {
                        // As it
                        // is
                        // already
                        // in process.

                        for (Object immediateRelation : immediateRelations)
                        {
                            if (!compareTo(getEntity(immediateRelation), originalEntity))
                            {
                                onParseRelation(relationEntity, pd, targetEntityMetadata, immediateRelation, relation,
                                        lazilyloaded);
                            }
                        }
                        setRelationToEntity(relationEntity, originalEntity, relation);
                        PersistenceCacheManager.addEntityToPersistenceCache(getEntity(relationEntity), pd,
                                PropertyAccessorHelper.getId(relationEntity, metadata));
                    }
                }
            }
        }
    }

    /**
     * 
     * Based on relation type, method invokes database to fetch relation
     * entities.
     * 
     * @param relation
     *            relation
     * @param metadata
     *            entity metadata
     * @param pd
     *            persistence delegator
     * @param entityId
     *            entity id
     * @param relationValue
     *            relational value
     * @param targetEntityMetadata
     *            relational entity's metadata.
     * 
     * @return list of fetched relations.
     */
    private List fetchRelations(final Relation relation, final EntityMetadata metadata, final PersistenceDelegator pd,
            final Object entityId, Object relationValue, EntityMetadata targetEntityMetadata)
    {
        List relationalEntities = new ArrayList();

        if ((relationValue != null && relation.isUnary()) || (relation.isJoinedByPrimaryKey()))
        {
            // Call it
            Object relationEntity = pd.getClient(targetEntityMetadata).find(relation.getTargetEntity(),
                    relationValue != null ? relationValue : entityId);
            if (relationEntity != null)
            {
                relationalEntities.add(relationEntity);
            }
        }
        else if (!relation.isUnary())
        {
            // Now these entities may be enhance entities and may not be as
            // well.
            Client associatedClient = pd.getClient(targetEntityMetadata);

            if (!MetadataUtils.useSecondryIndex(((ClientBase) associatedClient).getClientMetadata())
                    && MetadataUtils.indexSearchEnabled(targetEntityMetadata.getPersistenceUnit()))
            {

                relationalEntities = getAssociationBuilder().getAssociatedEntitiesFromIndex(
                        relation.getProperty().getDeclaringClass(), entityId, targetEntityMetadata.getEntityClazz(),
                        associatedClient);
            }
            else
            {
                relationalEntities = associatedClient.findByRelation(relation.getJoinColumnName(), entityId,
                        relation.getTargetEntity());
            }
        }
        return relationalEntities;
    }

    /**
     * Recursively fetches associated entities for a given entity
     * 
     * @param entity
     * @param relationsMap
     * @param client
     * @param m
     * @param pd
     * @return
     */
    public Object recursivelyFindEntities(Object entity, Map relationsMap, EntityMetadata m,
            PersistenceDelegator pd, boolean lazilyLoaded)
    {
        return handleAssociation(entity, relationsMap, m, pd, lazilyLoaded);

    }

    /**
     * Returns wrapped relations.
     * 
     * @param relationEntity
     * @return
     */
    private Map getPersistedRelations(Object relationEntity)
    {
        return relationEntity != null && relationEntity.getClass().isAssignableFrom(EnhanceEntity.class) ? ((EnhanceEntity) relationEntity)
                .getRelations() : null;
    }

    /**
     * Returns wrapped entity.
     * 
     * @param relationEntity
     * @return
     */
    private Object getEntity(Object relationEntity)
    {
        return relationEntity != null && relationEntity.getClass().isAssignableFrom(EnhanceEntity.class) ? ((EnhanceEntity) relationEntity)
                .getEntity() : relationEntity;
    }

    /**
     * On association using lucene.
     * 
     * @param m
     *            the m
     * @param client
     *            the client
     * @param ls
     *            the ls
     * @return the list
     */
    protected List onAssociationUsingLucene(EntityMetadata m, Client client, List ls)
    {
        Set rSet = fetchDataFromLucene(m.getEntityClazz(), client);
        List resultList = client.findAll(m.getEntityClazz(), null, rSet.toArray(new String[] {}));
        return m.getRelationNames() != null && !m.getRelationNames().isEmpty() ? resultList : transform(m, ls,
                resultList);
    }

    /**
     * Transform.
     * 
     * @param m
     *            the m
     * @param ls
     *            the ls
     * @param resultList
     *            the result list
     * @return the list
     */
    protected List transform(EntityMetadata m, List ls, List resultList)
    {
        if ((ls == null || ls.isEmpty()) && resultList != null && !resultList.isEmpty())
        {
            ls = new ArrayList(resultList.size());
        }
        for (Object r : resultList)
        {
            EnhanceEntity e = new EnhanceEntity(r, getId(r, m), null);
            ls.add(e);
        }
        return ls;
    }

    /**
     * Fetch data from lucene.
     * 
     * @param client
     *            the client
     * @return the sets the
     */
    protected Set fetchDataFromLucene(Class clazz, Client client)
    {
        // use lucene to query and get Pk's only.
        // go to client and get relation with values.!
        // populate EnhanceEntity
        Map results = client.getIndexManager().search(clazz, luceneQueryFromJPAQuery);
        Set rSet = new HashSet(results.values());
        return rSet;
    }

    /**
     * Gets the id.
     * 
     * @param entity
     *            the entity
     * @param metadata
     *            the metadata
     * @return the id
     */
    protected Object getId(Object entity, EntityMetadata metadata)
    {
        try
        {
            return PropertyAccessorHelper.getId(entity, metadata);
        }
        catch (PropertyAccessException e)
        {
            log.error("Error while Getting ID, Caused by: ", e);
            throw new EntityReaderException("Error while Getting ID for entity " + entity, e);
        }

    }

    /**
     * Compares original with relational entity.
     * 
     * @param relationalEntity
     * @param originalEntity
     * @return
     */
    private boolean compareTo(Object relationalEntity, Object originalEntity)
    {
        if (relationalEntity != null && originalEntity != null
                && relationalEntity.getClass().isAssignableFrom(originalEntity.getClass()))
        {
            EntityMetadata metadata = KunderaMetadataManager.getEntityMetadata(originalEntity.getClass());

            Object relationalEntityId = PropertyAccessorHelper.getId(relationalEntity, metadata);
            Object originalEntityId = PropertyAccessorHelper.getId(originalEntity, metadata);

            return relationalEntityId.equals(originalEntityId);
        }

        return false;
    }

    /**
     * Returns association builder instance.
     * 
     * @return association builder
     */
    private AssociationBuilder getAssociationBuilder()
    {
        if (this.associationBuilder == null)
        {
            this.associationBuilder = new AssociationBuilder();
        }

        return this.associationBuilder;

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy