com.impetus.kundera.graph.ObjectGraphBuilder Maven / Gradle / Ivy
/**
* 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.graph;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.collection.PersistentCollection;
import com.impetus.kundera.Constants;
import com.impetus.kundera.graph.NodeLink.LinkProperty;
import com.impetus.kundera.lifecycle.states.NodeState;
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.persistence.context.PersistenceCache;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.utils.DeepEquals;
import com.impetus.kundera.utils.ObjectUtils;
/**
* Responsible for generating {@link ObjectGraph} of nodes from a given entity
*
* @author amresh.singh
*/
public class ObjectGraphBuilder
{
private PersistenceCache persistenceCache;
public ObjectGraphBuilder(PersistenceCache pcCache)
{
this.persistenceCache = pcCache;
}
public ObjectGraph getObjectGraph(Object entity, NodeState initialNodeState)
{
// Initialize object graph
ObjectGraph objectGraph = new ObjectGraph();
this.persistenceCache = persistenceCache;
// Recursively build object graph and get head node.
Node headNode = getNode(entity, objectGraph, initialNodeState);
// Set head node into object graph
if (headNode != null)
{
objectGraph.setHeadNode(headNode);
}
return objectGraph;
}
public static String getNodeId(Object pk, Object nodeData)
{
StringBuffer strBuffer = new StringBuffer(nodeData.getClass().getName());
strBuffer.append(Constants.NODE_ID_SEPARATOR);
strBuffer.append(pk);
return strBuffer.toString();
}
public static String getNodeId(Object pk, Class> objectClass)
{
StringBuffer strBuffer = new StringBuffer(objectClass.getName());
strBuffer.append(Constants.NODE_ID_SEPARATOR);
strBuffer.append(pk);
return strBuffer.toString();
// return objectClass.getName() + Constants.NODE_ID_SEPARATOR +
// pk.toString();
}
/**
* Constructs and returns {@link Node} representation for a given entity
* object. Output is fully constructed graph with relationships embedded.
* Each node is put into graph
once it is constructed.
*
* @param entity
* @return
*/
private Node getNode(Object entity, ObjectGraph graph, NodeState initialNodeState)
{
EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(entity.getClass());
if (entityMetadata == null)
{
return null;
}
Object id = PropertyAccessorHelper.getId(entity, entityMetadata);
String nodeId = ObjectGraphUtils.getNodeId(id, entity);
// If this node is already there in graph (may happen for bidirectional
// relationship, do nothing and return null)
Node node = graph.getNode(nodeId);
if (node != null)
{
if (node.isGraphCompleted())
{
return node;
}
else
{
return null;
}
}
/*
* Node node = graph.getNode(nodeId); if(node != null) { return node; }
*/
// Construct this Node first, if one not already there in Persistence
// Cache
node = null;
Node nodeInPersistenceCache = persistenceCache.getMainCache().getNodeFromCache(nodeId);
// Make a deep copy of entity data
Object nodeDataCopy = ObjectUtils.deepCopy(entity);
if (nodeInPersistenceCache == null)
{
node = new Node(nodeId, nodeDataCopy, initialNodeState, persistenceCache, id);
}
else
{
node = nodeInPersistenceCache;
// Determine whether this node is dirty based on comparison between
// Node data and entity data
// If dirty, set the entity data into node and mark it as dirty
if (!DeepEquals.deepEquals(node.getData(), entity))
{
node.setData(nodeDataCopy);
node.setDirty(true);
}
else
{
node.setDirty(false);
}
// If node is NOT in managed state, its data needs to be
// replaced with the one provided in entity object
/*
* if(!
* node.getCurrentNodeState().getClass().equals(ManagedState.class))
* { node.setData(nodeDataCopy); node.setDirty(true); }
*/
}
// Put this node into object graph
graph.addNode(nodeId, node);
// Iterate over relations and construct children nodes
for (Relation relation : entityMetadata.getRelations())
{
// Child Object set in this entity
Object childObject = PropertyAccessorHelper.getObject(entity, relation.getProperty());
if (childObject != null)
{
// This child object could be either an entity(1-1 or M-1) or a
// collection of entities(1-M or M-M)
if (Collection.class.isAssignableFrom(childObject.getClass()))
{
// For each entity in the collection, construct a child node
// and add to graph
Collection childrenObjects = (Collection) childObject;
if(childrenObjects != null && !(childrenObjects instanceof PersistentCollection))
for (Object childObj : childrenObjects)
{
if (childObj != null)
{
addChildNodesToGraph(graph, node, relation, childObj, initialNodeState);
}
}
}
else
{
// Construct child node and add to graph
addChildNodesToGraph(graph, node, relation, childObject, initialNodeState);
}
}
}
// Means compelte graph is build.
node.setGraphCompleted(true);
return node;
}
/**
* @param graph
* @param node
* @param relation
* @param childObject
*/
private void addChildNodesToGraph(ObjectGraph graph, Node node, Relation relation, Object childObject,
NodeState initialNodeState)
{
// Construct child node for this child object via recursive call
Node childNode = getNode(childObject, graph, initialNodeState);
if (childNode != null)
{
// Construct Node Link for this relationship
NodeLink nodeLink = new NodeLink(node.getNodeId(), childNode.getNodeId());
nodeLink.setMultiplicity(relation.getType());
EntityMetadata metadata = KunderaMetadataManager.getEntityMetadata(node.getDataClass());
nodeLink.setLinkProperties(getLinkProperties(metadata, relation));
// Add Parent node to this child
childNode.addParentNode(nodeLink, node);
// Add child node to this node
node.addChildNode(nodeLink, childNode);
}
}
/**
*
* @param metadata
* Entity metadata of the parent node
* @param relation
* @return
*/
private Map getLinkProperties(EntityMetadata metadata, Relation relation)
{
Map linkProperties = new HashMap();
linkProperties.put(LinkProperty.LINK_NAME, MetadataUtils.getMappedName(metadata, relation));
linkProperties.put(LinkProperty.IS_SHARED_BY_PRIMARY_KEY, relation.isJoinedByPrimaryKey());
linkProperties.put(LinkProperty.IS_BIDIRECTIONAL, !relation.isUnary());
linkProperties.put(LinkProperty.IS_RELATED_VIA_JOIN_TABLE, relation.isRelatedViaJoinTable());
linkProperties.put(LinkProperty.PROPERTY, relation.getProperty());
// linkProperties.put(LinkProperty.BIDIRECTIONAL_PROPERTY, relation.ge);
linkProperties.put(LinkProperty.CASCADE, relation.getCascades());
if (relation.isRelatedViaJoinTable())
{
linkProperties.put(LinkProperty.JOIN_TABLE_METADATA, relation.getJoinTableMetadata());
}
// TODO: Add more link properties as required
return linkProperties;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy