package org.javers.core.graph;
import org.javers.common.collections.EnumerableFunction;
import org.javers.core.metamodel.object.*;
import org.javers.core.metamodel.type.*;
/**
* @author bartosz walacik
*/
class EdgeBuilder {
private final TypeMapper typeMapper;
private final NodeReuser nodeReuser;
private final CdoFactory cdoFactory;
EdgeBuilder(TypeMapper typeMapper, NodeReuser nodeReuser, CdoFactory cdoFactory) {
this.typeMapper = typeMapper;
this.nodeReuser = nodeReuser;
this.cdoFactory = cdoFactory;
}
String graphType(){
return cdoFactory.typeDesc();
}
/**
* @return node stub, could be redundant so check reuse context
*/
AbstractSingleEdge buildSingleEdge(ObjectNode node, JaversProperty singleRef) {
Object rawReference = node.getPropertyValue(singleRef);
Cdo cdo = cdoFactory.create(rawReference, createOwnerContext(node, singleRef));
if (!isShallowReference(singleRef, cdo)){
ObjectNode targetNode = buildNodeStubOrReuse(cdo);
return new SingleEdge(singleRef, targetNode);
}
return new ShallowSingleEdge(singleRef, cdo);
}
private boolean isShallowReference(JaversProperty reference, Cdo target){
return (reference.hasShallowReferenceAnn() ||
target.getManagedType() instanceof ShallowReferenceType);
}
private OwnerContext createOwnerContext(ObjectNode parentNode, JaversProperty property) {
return new PropertyOwnerContext(parentNode.getGlobalId(), property.getName());
}
MultiEdge createMultiEdge(JaversProperty containerProperty, EnumerableType enumerableType, ObjectNode node) {
MultiEdge multiEdge = new MultiEdge(containerProperty);
OwnerContext owner = createOwnerContext(node, containerProperty);
Object container = node.getPropertyValue(containerProperty);
EnumerableFunction edgeBuilder = null;
if (enumerableType instanceof KeyValueType){
edgeBuilder = new MultiEdgeMapBuilderFunction(multiEdge);
} else if (enumerableType instanceof ContainerType){
edgeBuilder = new MultiEdgeContainerBuilderFunction(multiEdge);
}
enumerableType.map(container, edgeBuilder, owner);
return multiEdge;
}
private class MultiEdgeContainerBuilderFunction implements EnumerableFunction {
private final MultiEdge multiEdge;
public MultiEdgeContainerBuilderFunction(MultiEdge multiEdge) {
this.multiEdge = multiEdge;
}
@Override
public Object apply(Object input, EnumerationAwareOwnerContext context) {
if (!isManagedPosition(input)){
return input;
}
ObjectNode objectNode = buildNodeStubOrReuse(cdoFactory.create(input, context));
multiEdge.addReferenceNode(objectNode);
return input;
}
boolean isManagedPosition(Object input){
return true;
}
}
private class MultiEdgeMapBuilderFunction extends MultiEdgeContainerBuilderFunction {
public MultiEdgeMapBuilderFunction(MultiEdge multiEdge) {
super(multiEdge);
}
boolean isManagedPosition(Object input){
return typeMapper.getJaversType(input.getClass()) instanceof ManagedType;
}
}
private ObjectNode buildNodeStubOrReuse(Cdo cdo){
if (nodeReuser.isReusable(cdo)){
return nodeReuser.getForReuse(cdo);
}
else {
return buildNodeStub(cdo);
}
}
ObjectNode buildNodeStub(Cdo cdo){
ObjectNode newStub = new ObjectNode(cdo);
nodeReuser.enqueueStub(newStub);
return newStub;
}
}