/************************************************************************ * Copyright (c) 2014 IoT-Solutions e.U. * * 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 iot.jcypher.domain.mapping.surrogate; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import iot.jcypher.domain.internal.DomainAccess.IRecursionExit; import iot.jcypher.domain.internal.DomainAccess.InternalDomainAccess; import iot.jcypher.domain.mapping.FieldMapping; import iot.jcypher.domain.mapping.DomainState.Relation.RelationUpdate; import iot.jcypher.graph.GrNode; import iot.jcypher.graph.GrProperty; public class InnerClassSurrogate { private transient Object realObject; private transient Constructor<?> constructor; private transient List<InnerClassSurrogate> toConstruct; private transient List<DeferredFieldMapping> parents; private transient List<DeferredFieldMapping> children; private transient List<DeferredPropertyMapping> propertyChildren; private transient IRecursionExit recursionExit; private transient int actResolutionDepth; private transient InternalDomainAccess id2ObjectMapper; private transient long nodeId; private transient List<RelationUpdate> relationUpdates; public InnerClassSurrogate(Constructor<?> constructor) { super(); this.constructor = constructor; } private void addToConstruct(InnerClassSurrogate ics) { if (this.realObject == null) { if (this.toConstruct == null) this.toConstruct = new ArrayList<InnerClassSurrogate>(); this.toConstruct.add(ics); } else { ics.constructAndFill(this.realObject); } } private void constructAndFill(Object obj) { try { this.realObject = this.constructor.newInstance(obj); } catch (Throwable e) { throw new RuntimeException(e); } fill(); } public void addChild(FieldMapping fm, Object obj) { if (fm.isInnerClassRefField()) { if (obj instanceof InnerClassSurrogate) { ((InnerClassSurrogate)obj).addToConstruct(this); } else { constructAndFill(obj); } } else { if (this.realObject == null) { if (this.children == null) this.children = new ArrayList<DeferredFieldMapping>(); this.children.add(new DeferredFieldMapping(fm, obj)); } else { fm.setFieldValue(this.realObject, obj); } } } private void fill() { if (this.children != null) { for (DeferredFieldMapping dfm : this.children) { dfm.fieldMapping.setFieldValue(this.realObject, dfm.object); } } if (this.propertyChildren != null) { for (DeferredPropertyMapping dpm : this.propertyChildren) { dpm.fieldMapping.mapPropertyToField(this.realObject, dpm.grNode); } } if (this.parents != null) { for (DeferredFieldMapping dfm : this.parents) { dfm.fieldMapping.setFieldValue(dfm.object, this.realObject); } } this.id2ObjectMapper.replace_Id2Object(this, this.realObject, this.nodeId); if (this.recursionExit != null) this.recursionExit.addRecursionExitObject(this.realObject, this.actResolutionDepth); if (this.toConstruct != null) { for (InnerClassSurrogate ics : this.toConstruct) { ics.constructAndFill(this.realObject); } } if (this.relationUpdates != null) { for (RelationUpdate ru : this.relationUpdates) { ru.updateWith(this.realObject); } } } /** * @param fm * @param obj * @param node * @return true if the property exists in the node */ public boolean addPropertyChild(FieldMapping fm, Object obj, GrNode node) { if (!fm.isInnerClassRefField()) { if (this.realObject == null) { if (this.propertyChildren == null) this.propertyChildren = new ArrayList<DeferredPropertyMapping>(); this.propertyChildren.add(new DeferredPropertyMapping(fm, obj, node)); GrProperty prop = node.getProperty(fm.getPropertyOrRelationName()); return prop != null; } else { return fm.mapPropertyToField(this.realObject, node); } } return false; } public void addParent(FieldMapping fm, Object obj) { if (this.realObject == null) { if (this.parents == null) this.parents = new ArrayList<DeferredFieldMapping>(); this.parents.add(new DeferredFieldMapping(fm, obj)); } else { fm.setFieldValue(obj, this.realObject); } } public Class<?> getRealClass() { return this.constructor.getDeclaringClass(); } public Object getRealObject() { return realObject; } public void setRecursionExit(IRecursionExit recursionExit) { this.recursionExit = recursionExit; } public void setActResolutionDepth(int actResolutionDepth) { this.actResolutionDepth = actResolutionDepth; } public void setId2ObjectMapper(InternalDomainAccess id2ObjectMapper) { this.id2ObjectMapper = id2ObjectMapper; } public void setNodeId(long nodeId) { this.nodeId = nodeId; } public void addRelationUpdate(RelationUpdate relationUpdate) { if (this.realObject == null) { if (this.relationUpdates == null) this.relationUpdates = new ArrayList<RelationUpdate>(); this.relationUpdates.add(relationUpdate); } else relationUpdate.updateWith(this.realObject); } /*****************************/ private class DeferredFieldMapping { protected FieldMapping fieldMapping; protected Object object; private DeferredFieldMapping(FieldMapping fieldMapping, Object object) { super(); this.fieldMapping = fieldMapping; this.object = object; } } /*****************************/ private class DeferredPropertyMapping extends DeferredFieldMapping { private GrNode grNode; private DeferredPropertyMapping(FieldMapping fieldMapping, Object object, GrNode n) { super(fieldMapping, object); this.grNode = n; } } }