X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.diagram%2Fsrc%2Forg%2Fsimantics%2Fdiagram%2Fsynchronization%2Fgraph%2FCopyAdvisorUtil.java;h=ab28463e84d5a8e3d3ae81af98b52f990393f167;hb=195c63dd5c7600170f594750de96793ebf06a0ad;hp=86a673952b2560e46df62aef86f627f9b0e919d8;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/CopyAdvisorUtil.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/CopyAdvisorUtil.java
index 86a673952..ab28463e8 100644
--- a/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/CopyAdvisorUtil.java
+++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/synchronization/graph/CopyAdvisorUtil.java
@@ -1,755 +1,756 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
- * in Industry THTH ry.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * VTT Technical Research Centre of Finland - initial API and implementation
- *******************************************************************************/
-package org.simantics.diagram.synchronization.graph;
-
-import gnu.trove.map.hash.THashMap;
-
-import java.util.Map;
-import java.util.Set;
-
-import org.simantics.databoard.Bindings;
-import org.simantics.databoard.binding.Binding;
-import org.simantics.databoard.type.Datatype;
-import org.simantics.db.ReadGraph;
-import org.simantics.db.Resource;
-import org.simantics.db.Statement;
-import org.simantics.db.WriteGraph;
-import org.simantics.db.common.utils.NameUtils;
-import org.simantics.db.exception.DatabaseException;
-import org.simantics.db.layer0.adapter.CopyHandler;
-import org.simantics.db.layer0.adapter.impl.FixedRootImportAdvisor;
-import org.simantics.db.layer0.util.ClipboardUtils;
-import org.simantics.db.layer0.util.SimanticsClipboard;
-import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
-import org.simantics.db.layer0.util.SimanticsClipboardImpl;
-import org.simantics.db.layer0.util.SimanticsKeys;
-import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
-import org.simantics.diagram.internal.DebugPolicy;
-import org.simantics.diagram.synchronization.CopyAdvisor;
-import org.simantics.diagram.synchronization.CopyAdvisor.Evaluation;
-import org.simantics.diagram.synchronization.ErrorHandler;
-import org.simantics.diagram.synchronization.IModifiableSynchronizationContext;
-import org.simantics.diagram.synchronization.StatementEvaluation;
-import org.simantics.diagram.synchronization.SynchronizationException;
-import org.simantics.diagram.synchronization.SynchronizationHints;
-import org.simantics.graph.db.TransferableGraphs;
-import org.simantics.graph.representation.TransferableGraph1;
-import org.simantics.layer0.Layer0;
-import org.simantics.utils.datastructures.BinaryFunction;
-
-/**
- * This class contains utility methods for the basic cut/copy operations
- * performed related to cut-copy-pasting diagram/configuration component and
- * composites.
- *
- *
- * Methods
- * {@link #cut(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
- * and
- * {@link #copy(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
- * are available for making it easier to properly invoke
- * {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
- * and
- * {@link CopyAdvisor#copy(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
- * operations in a diagram/graph transaction context.
- *
- *
- * Methods {@link #copy(WriteGraph, Resource, BinaryFunction)},
- * {@link #copy2(WriteGraph, Resource, BinaryFunction)},
- * {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)},
- * {@link #copy4(WriteGraph, Resource)} and
- * {@link #copy4(WriteGraph, Resource, CopyHandler)} offer differently
- * functioning versions of copying a single resource in the graph that are
- * mainly tuned for copying diagram elements and configuration components.
- *
- *
- * IMPORTANT: Note that copy, copy2 and copy3 cannot handle copying of ordered sets
- * properly.
- *
- * @author Tuukka Lehtonen
- */
-public class CopyAdvisorUtil {
-
- public static final boolean DEBUG_COPY = DebugPolicy.DEBUG_COPY_PASTE;
-
- /**
- * @param context a synchronization context instance, such as
- * {@link GraphToDiagramSynchronizer}
- * @param g handle for graph writing
- * @param ca the advisor for the copy operation
- * @param cut the resource that is about to be cut
- * @param sourceContainer the container from which the cut argument is about
- * to be removed
- * @param targetContainer the container into which the cut argument is about
- * to be moved
- * @return the result of
- * {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
- * @throws DatabaseException
- */
- public static Object cut(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca, Resource cut, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
- if (DEBUG_COPY)
- System.out.println("Attempting to cut component " + NameUtils.getSafeName(g, cut, true));
- try {
- context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
- context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
- return ca.cut(context, cut, sourceContainer, targetContainer);
- } catch (SynchronizationException e) {
- ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
- eh.error(e.getMessage(), e);
- } finally {
- context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
- context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
- }
- return null;
- }
-
- /**
- * @param context a synchronization context instance, such as
- * {@link GraphToDiagramSynchronizer}
- * @param g handle for graph writing
- * @param ca the advisor for the copy operation
- * @param copyOf the resource that is about to be copied
- * @param sourceContainer the container of the resource that will be copied
- * @param targetContainer the to-be container of the copied resource instance
- * @return the copied resource
- * @throws DatabaseException
- */
- public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
- Resource copyOf, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
- Resource resource = null;
- if (DEBUG_COPY)
- System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
- try {
- context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
- context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
- Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
- if (DEBUG_COPY)
- System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
- if (CopyAdvisor.SUPPORTED.contains(eval)) {
- Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer);
- if (DEBUG_COPY)
- System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
- if (copy instanceof Resource) {
- resource = (Resource) copy;
- } else {
- throw new UnsupportedOperationException("Cannot copy element " + copyOf);
- }
- }
- } catch (SynchronizationException e) {
- ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
- eh.error(e.getMessage(), e);
- // throwing exception allows canceling failed copy!
- throw new DatabaseException(e);
- } finally {
- context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
- context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
- }
- return resource;
- }
-
- /**
- * @param context a synchronization context instance, such as
- * {@link GraphToDiagramSynchronizer}
- * @param g handle for graph writing
- * @param ca the advisor for the copy operation
- * @param copyOf the resource that is about to be copied
- * @param sourceContainer the container of the resource that will be copied
- * @param targetContainer the to-be container of the copied resource instance
- * @param map a map for storing the correspondences between original and
- * copied objects. This is used to output data from the copy process.
- * @return the copied resource
- * @throws DatabaseException
- */
- public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
- Resource copyOf, Resource sourceContainer, Resource targetContainer, Map map)
- throws DatabaseException {
- Resource resource = null;
- if (DEBUG_COPY)
- System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
- try {
- context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
- context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
- Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
- if (DEBUG_COPY)
- System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
- if (CopyAdvisor.SUPPORTED.contains(eval)) {
- Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer, map);
- if (DEBUG_COPY) {
- System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
- System.out.println(" CopyAdvisor(" + ca + ").copy result map: " + map);
- }
- if (copy instanceof Resource) {
- resource = (Resource) copy;
- } else {
- throw new UnsupportedOperationException("Cannot copy element " + copyOf);
- }
- }
- } catch (SynchronizationException e) {
- ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
- eh.error(e.getMessage(), e);
- // throwing exception allows canceling failed copy!
- throw new DatabaseException(e);
- } finally {
- context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
- context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
- }
- return resource;
- }
-
- /**
- * Creates and returns a copy of the specified source resource based on the
- * standard Layer0 relation hierarchy by recursively including all resources
- * in the copy that the source and is composed of (see
- * {@link Layer0#IsComposedOf}). The routine will always copy at least all
- * L0.InstanceOf statements and tags related to its input resource. If the
- * copied resource has a value attached, it will also be copied.
- *
- * @param graph database write access
- * @param source the resource to start the copy from
- * @param advisor null
or a custom advisor to guide whether or
- * not to copy relations that are not inherited from L0.IsComposedOf.
- * This advisor cannot be used to say that non-composing relations
- * should perform recursive copy, only whether to copy the tested
- * statement of or not.
- * @return the copied resource
- * @throws DatabaseException
- */
- public static Resource copy(WriteGraph graph, Resource source, BinaryFunction advisor) throws DatabaseException {
- return copy(graph, source, 0, advisor, new THashMap());
- }
-
- /**
- * See {@link #copy(WriteGraph, Resource, BinaryFunction)}.
- *
- * @param graph
- * @param source
- * @param advisor
- * @param copyMap a map for storing the correspondences between original and
- * copied objects. This is used to output data from the copy process.
- * @return
- * @throws DatabaseException
- */
- public static Resource copy(WriteGraph graph, Resource source, BinaryFunction advisor, Map copyMap) throws DatabaseException {
- return copy(graph, source, 0, advisor, copyMap);
- }
-
- private static Resource copy(WriteGraph graph, Resource source, int level, BinaryFunction advisor, Map copyMap) throws DatabaseException {
- if (DEBUG_COPY)
- System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
-
- Resource copy = (Resource) copyMap.get(source);
- if (copy != null) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
- return copy;
- }
-
- Layer0 L0 = Layer0.getInstance(graph);
- copy = graph.newResource();
- copyMap.put(source, copy);
- for (Resource type : graph.getObjects(source, L0.InstanceOf))
- graph.claim(copy, L0.InstanceOf, null, type);
-
- if (graph.hasValue(source)) {
- Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
- Binding b = Bindings.getBinding(dt);
- graph.claimValue(copy, graph.getValue(source, b), b);
- }
-
- // Copy tags
- for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
- if (stm.isAsserted(source))
- continue;
- if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\tcopying tag ("
- + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
- + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
- graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
- }
- }
-
- for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
- Resource relation = stm.getPredicate();
-
- // InstanceOf statements are handled separately, silently ignore them here.
- if (L0.InstanceOf.equals(relation))
- continue;
-
- // Don't copy asserted relations!
- if (stm.isAsserted(source)) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tSkipping asserted statement");
- continue;
- }
-
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
-
- Resource subject = stm.getSubject();
- Resource inverse = graph.getPossibleInverse(relation);
- boolean addInverse = false;
- Resource obj = stm.getObject();
- Resource propType = graph.getPossibleType(obj, L0.Literal);
-
- // §1 only L0.IsComposedOf and its subrelations can be considered to be copied automatically
-
- if (propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
- if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tclaim enumeration statement");
- graph.claim(copy, relation, null, obj);
- } else {
- if (inverse != null)
- addInverse = graph.hasStatement(obj, inverse, subject);
-
- // Copy instantiated properties, not asserted ones.
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tcopy whole object");
- Resource clone = copy(graph, obj, level + 1, advisor, copyMap);
- graph.claim(copy, relation, clone);
- }
- } else {
- if (advisor != null) {
- Boolean result = advisor.call(graph, stm);
- if (Boolean.TRUE.equals(result)) {
- // Don't clone the object, just add relation to the same object.
- if (inverse != null)
- addInverse = graph.hasStatement(obj, inverse, subject);
-
- if (DEBUG_COPY) {
- System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy.claim(" + NameUtils.getSafeName(graph, copy) + ", "
- + NameUtils.getSafeName(graph, relation) + ", "
- + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
- + NameUtils.getSafeName(graph, obj));
- }
-
- graph.claim(copy, relation, addInverse ? inverse : null, obj);
- }
- } else {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tskipping statement");
- }
- }
- }
- return copy;
- }
-
- /**
- * Creates and returns a copy of the specified source resource based on the
- * standard Layer0 relation hierarchy by recursively including all resources
- * in the copy that the source and is composed of (see
- * {@link Layer0#IsComposedOf}). A customizable advisor function can be used
- * to guide the copy process. The routine will always copy at least all
- * L0.InstanceOf statements and tags related to its input resource. If the
- * copied resource has a value attached, it will also be copied.
- *
- * @param graph database write access
- * @param source the resource to start the copy from
- * @param advisor null
or a custom advisor to guide the copy
- * process according to the specifications of
- * {@link StatementEvaluation}. Every copied statement besides
- * L0.InstanceOf and tags will be evaluated by this advisor.
- * @return the copied resource
- * @throws DatabaseException
- */
- public static Resource copy2(WriteGraph graph, Resource source,
- BinaryFunction advisor) throws DatabaseException {
- return copy2(graph, source, 0, advisor, new THashMap());
- }
-
- /**
- * See {@link #copy2(WriteGraph, Resource, BinaryFunction)}.
- *
- * @param graph
- * @param source
- * @param advisor
- * @param copyMap a map for storing the correspondences between original and
- * copied objects. This is used to output data from the copy process.
- * @return
- * @throws DatabaseException
- */
- public static Resource copy2(WriteGraph graph, Resource source,
- BinaryFunction advisor, Map copyMap)
- throws DatabaseException {
- return copy2(graph, source, 0, advisor, copyMap);
- }
-
- private static Resource copy2(final WriteGraph graph, final Resource source, final int level,
- BinaryFunction advisor, Map copyMap)
- throws DatabaseException {
- if (DEBUG_COPY)
- System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
-
- Resource copy = (Resource) copyMap.get(source);
- if (copy != null) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
- return copy;
- }
-
- Layer0 L0 = Layer0.getInstance(graph);
- copy = graph.newResource();
- copyMap.put(source, copy);
- for (Resource type : graph.getObjects(source, L0.InstanceOf))
- graph.claim(copy, L0.InstanceOf, null, type);
-
- if (graph.hasValue(source)) {
- Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
- Binding b = Bindings.getBinding(dt);
- graph.claimValue(copy, graph.getValue(source, b), b);
- }
-
- // Copy tags
- for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
- if (stm.isAsserted(source))
- continue;
- if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\tcopying tag ("
- + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
- + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
- graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
- }
- }
-
- for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
- Resource relation = stm.getPredicate();
-
- // InstanceOf statements are handled separately, silently ignore them here.
- if (L0.InstanceOf.equals(relation))
- continue;
-
- // Don't copy asserted relations!
- if (stm.isAsserted(source)) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\tskipping asserted statement (" + NameUtils.toString(graph, stm) + ")");
- continue;
- }
-
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
-
- Resource subject = stm.getSubject();
- Resource inverse = graph.getPossibleInverse(relation);
- Resource obj = stm.getObject();
- Resource propType = graph.getPossibleType(obj, L0.Literal);
- boolean addInverse = false;
- boolean forceIncludeAndFollow = false;
-
- switch (evaluate(graph, stm, advisor)) {
- case SKIP:
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tskipping statement");
- break;
-
- case INCLUDE:
- {
- // Don't clone the object, just add relation to the same object.
- if (inverse != null)
- addInverse = graph.hasStatement(obj, inverse, subject);
-
- if (DEBUG_COPY) {
- System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy2.claim(" + NameUtils.getSafeName(graph, copy) + ", "
- + NameUtils.getSafeName(graph, relation) + ", "
- + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
- + NameUtils.getSafeName(graph, obj));
- }
-
- graph.claim(copy, relation, addInverse ? inverse : null, obj);
- break;
- }
-
- case INCLUDE_AND_FOLLOW:
- // Force follow-through in the default copy logic
- forceIncludeAndFollow = true;
- // NOTE: intentional fall-through here
-
- case USE_DEFAULT:
- {
- if (forceIncludeAndFollow || propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
- if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
- // This logic is applied only for enumeration property
- // statements that should not have an inverse in any case.
- if (DEBUG_COPY) {
- System.out.println("[" + level + "]\t\tclaim enumeration statement("
- + NameUtils.getSafeName(graph, copy) + ", "
- + NameUtils.getSafeName(graph, relation)+ ", null, "
- + NameUtils.getSafeName(graph, obj));
- }
- graph.claim(copy, relation, null, obj);
- } else {
- // This logic is applied for other properties besides enumerations
- if (inverse != null)
- addInverse = graph.hasStatement(obj, inverse, subject);
-
- // Copy instantiated properties, not asserted ones.
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tcopy whole object");
-
- Resource clone = copy2(graph, obj, level + 1, advisor, copyMap);
- graph.claim(copy, relation, inverse, clone);
- }
- } else {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tskipping statement");
- }
- }
- }
- }
- return copy;
- }
-
- /**
- * Creates and returns a copy of the specified source resource based on the
- * standard Layer0 relation hierarchy by recursively including all resources
- * in the copy that the source and is composed of (see
- * {@link Layer0#IsComposedOf}). A customizable advisor function can be used
- * to guide the copy process. The routine will always copy at least all
- * L0.InstanceOf statements and tags related to its input resource. If the
- * copied resource has a value attached, it will also be copied.
- *
- * Works exactly like {@link #copy2(WriteGraph, Resource, BinaryFunction)}
- * but uses the model
argument to make sure that the copy
- * process does not propagate outside of the model. Any references that go
- * to resources with URIs that are not in the model's namespace are copied
- * as unidirectional.
- *
- * @param graph database write access
- * @param source the resource to start the copy from
- * @param model the model containing the source object, used to keep the
- * copy process model-local
- * @param advisor null
or a custom advisor to guide the copy
- * process according to the specifications of
- * {@link StatementEvaluation}. Every copied statement besides
- * L0.InstanceOf and tags will be evaluated by this advisor.
- * @return the copied resource
- * @throws DatabaseException
- */
- public static Resource copy3(WriteGraph graph, Resource source, Resource model,
- BinaryFunction advisor) throws DatabaseException {
- String modelURI = graph.getURI(model);
- return copy3(graph, modelURI, source, 0, advisor, new THashMap());
- }
-
- /**
- * See {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)}.
- *
- * @param graph
- * @param source
- * @param model
- * @param advisor
- * @param copyMap a map for storing the correspondences between original and
- * copied objects. This is used to output data from the copy process.
- * @return
- * @throws DatabaseException
- */
- public static Resource copy3(WriteGraph graph, Resource source, Resource model,
- BinaryFunction advisor, Map copyMap) throws DatabaseException {
- String modelURI = graph.getURI(model);
- return copy3(graph, modelURI, source, 0, advisor, copyMap);
- }
-
- private static Resource copy3(WriteGraph graph, String modelURI, Resource source, int level,
- BinaryFunction advisor, Map copyMap)
- throws DatabaseException {
- if (DEBUG_COPY)
- System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
-
- Resource copy = (Resource) copyMap.get(source);
- if (copy != null) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
- return copy;
- }
-
- Layer0 L0 = Layer0.getInstance(graph);
- copy = graph.newResource();
- copyMap.put(source, copy);
- for (Resource type : graph.getObjects(source, L0.InstanceOf))
- graph.claim(copy, L0.InstanceOf, null, type);
-
- if (graph.hasValue(source)) {
- Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
- Binding b = Bindings.getBinding(dt);
- graph.claimValue(copy, graph.getValue(source, b), b);
- }
-
- // Copy tags
- for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
- if (stm.isAsserted(source))
- continue;
- if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\tcopying tag ("
- + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
- + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
- graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
- }
- }
-
- for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
- Resource relation = stm.getPredicate();
-
- // InstanceOf statements are handled separately, silently ignore them here.
- if (L0.InstanceOf.equals(relation))
- continue;
-
- // Don't copy asserted relations!
- if (stm.isAsserted(source)) {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\tskipping asserted statement (" + NameUtils.toString(graph, stm) + ")");
- continue;
- }
-
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
-
- Resource subject = stm.getSubject();
- Resource inverse = graph.getPossibleInverse(relation);
- Resource obj = stm.getObject();
- Resource propType = graph.getPossibleType(obj, L0.Literal);
- boolean addInverse = false;
- boolean forceIncludeAndFollow = false;
-
- switch (evaluate(graph, stm, advisor)) {
- case SKIP:
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tskipping statement");
- break;
-
- case INCLUDE:
- {
- // Don't clone the object, just add relation to the same object.
- if (inverse != null)
- addInverse = graph.hasStatement(obj, inverse, subject);
-
- if (DEBUG_COPY) {
- System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy2.claim(" + NameUtils.getSafeName(graph, copy) + ", "
- + NameUtils.getSafeName(graph, relation) + ", "
- + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
- + NameUtils.getSafeName(graph, obj));
- }
-
- graph.claim(copy, relation, addInverse ? inverse : null, obj);
- break;
- }
-
- case INCLUDE_AND_FOLLOW:
- // Force follow-through in the default copy logic
- forceIncludeAndFollow = true;
- // NOTE: intentional fall-through here
-
- case USE_DEFAULT:
- {
- if (forceIncludeAndFollow || propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
- if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
- // This logic is applied only for enumeration property
- // statements that should not have an inverse in any case.
- if (DEBUG_COPY) {
- System.out.println("[" + level + "]\t\tclaim enumeration statement("
- + NameUtils.getSafeName(graph, copy) + ", "
- + NameUtils.getSafeName(graph, relation)+ ", null, "
- + NameUtils.getSafeName(graph, obj));
- }
- graph.claim(copy, relation, null, obj);
- } else {
- // This logic is applied for other properties besides enumerations
- if (inverse != null)
- addInverse = graph.hasStatement(obj, inverse, subject);
-
- String objectURI = graph.getPossibleURI(obj);
-
- if(objectURI != null && !objectURI.startsWith(modelURI)) {
-
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tclaim ontological reference");
-
- graph.claim(copy, relation, null, obj);
-
- } else {
-
- // Copy instantiated properties, not asserted ones.
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tcopy whole object");
-
- Resource clone = copy3(graph, modelURI, obj, level + 1, advisor, copyMap);
- graph.claim(copy, relation, inverse, clone);
-
- }
-
- }
- } else {
- if (DEBUG_COPY)
- System.out.println("[" + level + "]\t\tskipping statement");
- }
- }
- }
- }
- return copy;
- }
-
- protected static StatementEvaluation evaluate(ReadGraph graph, Statement stm, BinaryFunction tester) {
- if (tester == null)
- return StatementEvaluation.USE_DEFAULT;
- return tester.call(graph, stm);
- }
-
- /**
- * Equal to
- * copy4(graph, source, graph.adapt(source, CopyHandler.class)))
- * .
- *
- * @param graph database write access
- * @param source the resource to start the copy from
- * @return the copied resource
- * @throws DatabaseException
- */
- public static Resource copy4(WriteGraph graph, Resource source) throws DatabaseException {
- CopyHandler handler = graph.adapt(source, CopyHandler.class);
- return copy4(graph, source, handler);
- }
-
- /**
- * Creates and returns a copy of the specified source resource based on
- * transferable graph export and import. The TG representation shall be
- * generated by the specified {@link CopyHandler} into a
- * {@link SimanticsClipboard} instance from where it is read back as
- * {@link TransferableGraph1} and imported into the database through
- * {@link TransferableGraphs#importGraph1(WriteGraph, TransferableGraph1, org.simantics.graph.db.IImportAdvisor)}.
- *
- * @param graph database write access
- * @param source the resource to start the copy from
- * @param copyHandler the handler to use for generating the transferable
- * graph representation from the copied resource
- * @return the copied resource
- * @throws DatabaseException
- */
- public static Resource copy4(WriteGraph graph, Resource source, CopyHandler copyHandler) throws DatabaseException {
- SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
- copyHandler.copyToClipboard(graph, builder);
-
- for(Set object : builder.getContents()) {
- TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
- if(tg != null) {
- FixedRootImportAdvisor advisor = new FixedRootImportAdvisor();
- TransferableGraphs.importGraph1(graph, tg, advisor);
- return advisor.getRoot();
- }
- }
-
- String uri = graph.getPossibleURI(source);
- throw new DatabaseException("Failed to copy resource " + NameUtils.getSafeName(graph, source, true)
- + (uri != null ? " with URI " + uri : ""));
- }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.synchronization.graph;
+
+import gnu.trove.map.hash.THashMap;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Statement;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.adapter.CopyHandler;
+import org.simantics.db.layer0.adapter.impl.FixedRootImportAdvisor;
+import org.simantics.db.layer0.util.ClipboardUtils;
+import org.simantics.db.layer0.util.SimanticsClipboard;
+import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
+import org.simantics.db.layer0.util.SimanticsClipboardImpl;
+import org.simantics.db.layer0.util.SimanticsKeys;
+import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
+import org.simantics.diagram.internal.DebugPolicy;
+import org.simantics.diagram.synchronization.CopyAdvisor;
+import org.simantics.diagram.synchronization.CopyAdvisor.Evaluation;
+import org.simantics.diagram.synchronization.ErrorHandler;
+import org.simantics.diagram.synchronization.IModifiableSynchronizationContext;
+import org.simantics.diagram.synchronization.StatementEvaluation;
+import org.simantics.diagram.synchronization.SynchronizationException;
+import org.simantics.diagram.synchronization.SynchronizationHints;
+import org.simantics.graph.db.TransferableGraphs;
+import org.simantics.graph.representation.TransferableGraph1;
+import org.simantics.layer0.Layer0;
+
+/**
+ * This class contains utility methods for the basic cut/copy operations
+ * performed related to cut-copy-pasting diagram/configuration component and
+ * composites.
+ *
+ *
+ * Methods
+ * {@link #cut(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
+ * and
+ * {@link #copy(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
+ * are available for making it easier to properly invoke
+ * {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
+ * and
+ * {@link CopyAdvisor#copy(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
+ * operations in a diagram/graph transaction context.
+ *
+ *
+ * Methods {@link #copy(WriteGraph, Resource, BinaryFunction)},
+ * {@link #copy2(WriteGraph, Resource, BinaryFunction)},
+ * {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)},
+ * {@link #copy4(WriteGraph, Resource)} and
+ * {@link #copy4(WriteGraph, Resource, CopyHandler)} offer differently
+ * functioning versions of copying a single resource in the graph that are
+ * mainly tuned for copying diagram elements and configuration components.
+ *
+ *
+ * IMPORTANT: Note that copy, copy2 and copy3 cannot handle copying of ordered sets
+ * properly.
+ *
+ * @author Tuukka Lehtonen
+ */
+public class CopyAdvisorUtil {
+
+ public static final boolean DEBUG_COPY = DebugPolicy.DEBUG_COPY_PASTE;
+
+ /**
+ * @param context a synchronization context instance, such as
+ * {@link GraphToDiagramSynchronizer}
+ * @param g handle for graph writing
+ * @param ca the advisor for the copy operation
+ * @param cut the resource that is about to be cut
+ * @param sourceContainer the container from which the cut argument is about
+ * to be removed
+ * @param targetContainer the container into which the cut argument is about
+ * to be moved
+ * @return the result of
+ * {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
+ * @throws DatabaseException
+ */
+ public static Object cut(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca, Resource cut, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
+ if (DEBUG_COPY)
+ System.out.println("Attempting to cut component " + NameUtils.getSafeName(g, cut, true));
+ try {
+ context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
+ context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
+ return ca.cut(context, cut, sourceContainer, targetContainer);
+ } catch (SynchronizationException e) {
+ ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
+ eh.error(e.getMessage(), e);
+ } finally {
+ context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
+ context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
+ }
+ return null;
+ }
+
+ /**
+ * @param context a synchronization context instance, such as
+ * {@link GraphToDiagramSynchronizer}
+ * @param g handle for graph writing
+ * @param ca the advisor for the copy operation
+ * @param copyOf the resource that is about to be copied
+ * @param sourceContainer the container of the resource that will be copied
+ * @param targetContainer the to-be container of the copied resource instance
+ * @return the copied resource
+ * @throws DatabaseException
+ */
+ public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
+ Resource copyOf, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
+ Resource resource = null;
+ if (DEBUG_COPY)
+ System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
+ try {
+ context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
+ context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
+ Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
+ if (DEBUG_COPY)
+ System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
+ if (CopyAdvisor.SUPPORTED.contains(eval)) {
+ Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer);
+ if (DEBUG_COPY)
+ System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
+ if (copy instanceof Resource) {
+ resource = (Resource) copy;
+ } else {
+ throw new UnsupportedOperationException("Cannot copy element " + copyOf);
+ }
+ }
+ } catch (SynchronizationException e) {
+ ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
+ eh.error(e.getMessage(), e);
+ // throwing exception allows canceling failed copy!
+ throw new DatabaseException(e);
+ } finally {
+ context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
+ context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
+ }
+ return resource;
+ }
+
+ /**
+ * @param context a synchronization context instance, such as
+ * {@link GraphToDiagramSynchronizer}
+ * @param g handle for graph writing
+ * @param ca the advisor for the copy operation
+ * @param copyOf the resource that is about to be copied
+ * @param sourceContainer the container of the resource that will be copied
+ * @param targetContainer the to-be container of the copied resource instance
+ * @param map a map for storing the correspondences between original and
+ * copied objects. This is used to output data from the copy process.
+ * @return the copied resource
+ * @throws DatabaseException
+ */
+ public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
+ Resource copyOf, Resource sourceContainer, Resource targetContainer, Map map)
+ throws DatabaseException {
+ Resource resource = null;
+ if (DEBUG_COPY)
+ System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
+ try {
+ context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
+ context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
+ Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
+ if (DEBUG_COPY)
+ System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
+ if (CopyAdvisor.SUPPORTED.contains(eval)) {
+ Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer, map);
+ if (DEBUG_COPY) {
+ System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
+ System.out.println(" CopyAdvisor(" + ca + ").copy result map: " + map);
+ }
+ if (copy instanceof Resource) {
+ resource = (Resource) copy;
+ } else {
+ throw new UnsupportedOperationException("Cannot copy element " + copyOf);
+ }
+ }
+ } catch (SynchronizationException e) {
+ ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
+ eh.error(e.getMessage(), e);
+ // throwing exception allows canceling failed copy!
+ throw new DatabaseException(e);
+ } finally {
+ context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
+ context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
+ }
+ return resource;
+ }
+
+ /**
+ * Creates and returns a copy of the specified source resource based on the
+ * standard Layer0 relation hierarchy by recursively including all resources
+ * in the copy that the source and is composed of (see
+ * {@link Layer0#IsComposedOf}). The routine will always copy at least all
+ * L0.InstanceOf statements and tags related to its input resource. If the
+ * copied resource has a value attached, it will also be copied.
+ *
+ * @param graph database write access
+ * @param source the resource to start the copy from
+ * @param advisor null
or a custom advisor to guide whether or
+ * not to copy relations that are not inherited from L0.IsComposedOf.
+ * This advisor cannot be used to say that non-composing relations
+ * should perform recursive copy, only whether to copy the tested
+ * statement of or not.
+ * @return the copied resource
+ * @throws DatabaseException
+ */
+ public static Resource copy(WriteGraph graph, Resource source, BiFunction advisor) throws DatabaseException {
+ return copy(graph, source, 0, advisor, new THashMap());
+ }
+
+ /**
+ * See {@link #copy(WriteGraph, Resource, BinaryFunction)}.
+ *
+ * @param graph
+ * @param source
+ * @param advisor
+ * @param copyMap a map for storing the correspondences between original and
+ * copied objects. This is used to output data from the copy process.
+ * @return
+ * @throws DatabaseException
+ */
+ public static Resource copy(WriteGraph graph, Resource source, BiFunction advisor, Map copyMap) throws DatabaseException {
+ return copy(graph, source, 0, advisor, copyMap);
+ }
+
+ private static Resource copy(WriteGraph graph, Resource source, int level, BiFunction advisor, Map copyMap) throws DatabaseException {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
+
+ Resource copy = (Resource) copyMap.get(source);
+ if (copy != null) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
+ return copy;
+ }
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ copy = graph.newResource();
+ copyMap.put(source, copy);
+ for (Resource type : graph.getObjects(source, L0.InstanceOf))
+ graph.claim(copy, L0.InstanceOf, null, type);
+
+ if (graph.hasValue(source)) {
+ Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
+ Binding b = Bindings.getBinding(dt);
+ graph.claimValue(copy, graph.getValue(source, b), b);
+ }
+
+ // Copy tags
+ for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
+ if (stm.isAsserted(source))
+ continue;
+ if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\tcopying tag ("
+ + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
+ + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
+ graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
+ }
+ }
+
+ for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
+ Resource relation = stm.getPredicate();
+
+ // InstanceOf statements are handled separately, silently ignore them here.
+ if (L0.InstanceOf.equals(relation))
+ continue;
+
+ // Don't copy asserted relations!
+ if (stm.isAsserted(source)) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tSkipping asserted statement");
+ continue;
+ }
+
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
+
+ Resource subject = stm.getSubject();
+ Resource inverse = graph.getPossibleInverse(relation);
+ boolean addInverse = false;
+ Resource obj = stm.getObject();
+ Resource propType = graph.getPossibleType(obj, L0.Literal);
+
+ // §1 only L0.IsComposedOf and its subrelations can be considered to be copied automatically
+
+ if (propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
+ if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tclaim enumeration statement");
+ graph.claim(copy, relation, null, obj);
+ } else {
+ if (inverse != null)
+ addInverse = graph.hasStatement(obj, inverse, subject);
+
+ // Copy instantiated properties, not asserted ones.
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tcopy whole object");
+ Resource clone = copy(graph, obj, level + 1, advisor, copyMap);
+ graph.claim(copy, relation, clone);
+ }
+ } else {
+ if (advisor != null) {
+ Boolean result = advisor.apply(graph, stm);
+ if (Boolean.TRUE.equals(result)) {
+ // Don't clone the object, just add relation to the same object.
+ if (inverse != null)
+ addInverse = graph.hasStatement(obj, inverse, subject);
+
+ if (DEBUG_COPY) {
+ System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy.claim(" + NameUtils.getSafeName(graph, copy) + ", "
+ + NameUtils.getSafeName(graph, relation) + ", "
+ + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
+ + NameUtils.getSafeName(graph, obj));
+ }
+
+ graph.claim(copy, relation, addInverse ? inverse : null, obj);
+ }
+ } else {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tskipping statement");
+ }
+ }
+ }
+ return copy;
+ }
+
+ /**
+ * Creates and returns a copy of the specified source resource based on the
+ * standard Layer0 relation hierarchy by recursively including all resources
+ * in the copy that the source and is composed of (see
+ * {@link Layer0#IsComposedOf}). A customizable advisor function can be used
+ * to guide the copy process. The routine will always copy at least all
+ * L0.InstanceOf statements and tags related to its input resource. If the
+ * copied resource has a value attached, it will also be copied.
+ *
+ * @param graph database write access
+ * @param source the resource to start the copy from
+ * @param advisor null
or a custom advisor to guide the copy
+ * process according to the specifications of
+ * {@link StatementEvaluation}. Every copied statement besides
+ * L0.InstanceOf and tags will be evaluated by this advisor.
+ * @return the copied resource
+ * @throws DatabaseException
+ */
+ public static Resource copy2(WriteGraph graph, Resource source,
+ BiFunction advisor) throws DatabaseException {
+ return copy2(graph, source, 0, advisor, new THashMap());
+ }
+
+ /**
+ * See {@link #copy2(WriteGraph, Resource, BinaryFunction)}.
+ *
+ * @param graph
+ * @param source
+ * @param advisor
+ * @param copyMap a map for storing the correspondences between original and
+ * copied objects. This is used to output data from the copy process.
+ * @return
+ * @throws DatabaseException
+ */
+ public static Resource copy2(WriteGraph graph, Resource source,
+ BiFunction advisor, Map copyMap)
+ throws DatabaseException {
+ return copy2(graph, source, 0, advisor, copyMap);
+ }
+
+ private static Resource copy2(final WriteGraph graph, final Resource source, final int level,
+ BiFunction advisor, Map copyMap)
+ throws DatabaseException {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
+
+ Resource copy = (Resource) copyMap.get(source);
+ if (copy != null) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
+ return copy;
+ }
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ copy = graph.newResource();
+ copyMap.put(source, copy);
+ for (Resource type : graph.getObjects(source, L0.InstanceOf))
+ graph.claim(copy, L0.InstanceOf, null, type);
+
+ if (graph.hasValue(source)) {
+ Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
+ Binding b = Bindings.getBinding(dt);
+ graph.claimValue(copy, graph.getValue(source, b), b);
+ }
+
+ // Copy tags
+ for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
+ if (stm.isAsserted(source))
+ continue;
+ if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\tcopying tag ("
+ + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
+ + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
+ graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
+ }
+ }
+
+ for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
+ Resource relation = stm.getPredicate();
+
+ // InstanceOf statements are handled separately, silently ignore them here.
+ if (L0.InstanceOf.equals(relation))
+ continue;
+
+ // Don't copy asserted relations!
+ if (stm.isAsserted(source)) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\tskipping asserted statement (" + NameUtils.toString(graph, stm) + ")");
+ continue;
+ }
+
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
+
+ Resource subject = stm.getSubject();
+ Resource inverse = graph.getPossibleInverse(relation);
+ Resource obj = stm.getObject();
+ Resource propType = graph.getPossibleType(obj, L0.Literal);
+ boolean addInverse = false;
+ boolean forceIncludeAndFollow = false;
+
+ switch (evaluate(graph, stm, advisor)) {
+ case SKIP:
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tskipping statement");
+ break;
+
+ case INCLUDE:
+ {
+ // Don't clone the object, just add relation to the same object.
+ if (inverse != null)
+ addInverse = graph.hasStatement(obj, inverse, subject);
+
+ if (DEBUG_COPY) {
+ System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy2.claim(" + NameUtils.getSafeName(graph, copy) + ", "
+ + NameUtils.getSafeName(graph, relation) + ", "
+ + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
+ + NameUtils.getSafeName(graph, obj));
+ }
+
+ graph.claim(copy, relation, addInverse ? inverse : null, obj);
+ break;
+ }
+
+ case INCLUDE_AND_FOLLOW:
+ // Force follow-through in the default copy logic
+ forceIncludeAndFollow = true;
+ // NOTE: intentional fall-through here
+
+ case USE_DEFAULT:
+ {
+ if (forceIncludeAndFollow || propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
+ if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
+ // This logic is applied only for enumeration property
+ // statements that should not have an inverse in any case.
+ if (DEBUG_COPY) {
+ System.out.println("[" + level + "]\t\tclaim enumeration statement("
+ + NameUtils.getSafeName(graph, copy) + ", "
+ + NameUtils.getSafeName(graph, relation)+ ", null, "
+ + NameUtils.getSafeName(graph, obj));
+ }
+ graph.claim(copy, relation, null, obj);
+ } else {
+ // This logic is applied for other properties besides enumerations
+ if (inverse != null)
+ addInverse = graph.hasStatement(obj, inverse, subject);
+
+ // Copy instantiated properties, not asserted ones.
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tcopy whole object");
+
+ Resource clone = copy2(graph, obj, level + 1, advisor, copyMap);
+ graph.claim(copy, relation, inverse, clone);
+ }
+ } else {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tskipping statement");
+ }
+ }
+ }
+ }
+ return copy;
+ }
+
+ /**
+ * Creates and returns a copy of the specified source resource based on the
+ * standard Layer0 relation hierarchy by recursively including all resources
+ * in the copy that the source and is composed of (see
+ * {@link Layer0#IsComposedOf}). A customizable advisor function can be used
+ * to guide the copy process. The routine will always copy at least all
+ * L0.InstanceOf statements and tags related to its input resource. If the
+ * copied resource has a value attached, it will also be copied.
+ *
+ * Works exactly like {@link #copy2(WriteGraph, Resource, BinaryFunction)}
+ * but uses the model
argument to make sure that the copy
+ * process does not propagate outside of the model. Any references that go
+ * to resources with URIs that are not in the model's namespace are copied
+ * as unidirectional.
+ *
+ * @param graph database write access
+ * @param source the resource to start the copy from
+ * @param model the model containing the source object, used to keep the
+ * copy process model-local
+ * @param advisor null
or a custom advisor to guide the copy
+ * process according to the specifications of
+ * {@link StatementEvaluation}. Every copied statement besides
+ * L0.InstanceOf and tags will be evaluated by this advisor.
+ * @return the copied resource
+ * @throws DatabaseException
+ */
+ public static Resource copy3(WriteGraph graph, Resource source, Resource model,
+ BiFunction advisor) throws DatabaseException {
+ String modelURI = graph.getURI(model);
+ return copy3(graph, modelURI, source, 0, advisor, new THashMap());
+ }
+
+ /**
+ * See {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)}.
+ *
+ * @param graph
+ * @param source
+ * @param model
+ * @param advisor
+ * @param copyMap a map for storing the correspondences between original and
+ * copied objects. This is used to output data from the copy process.
+ * @return
+ * @throws DatabaseException
+ */
+ public static Resource copy3(WriteGraph graph, Resource source, Resource model,
+ BiFunction advisor, Map copyMap) throws DatabaseException {
+ String modelURI = graph.getURI(model);
+ return copy3(graph, modelURI, source, 0, advisor, copyMap);
+ }
+
+ private static Resource copy3(WriteGraph graph, String modelURI, Resource source, int level,
+ BiFunction advisor, Map copyMap)
+ throws DatabaseException {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
+
+ Resource copy = (Resource) copyMap.get(source);
+ if (copy != null) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
+ return copy;
+ }
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ copy = graph.newResource();
+ copyMap.put(source, copy);
+ for (Resource type : graph.getObjects(source, L0.InstanceOf))
+ graph.claim(copy, L0.InstanceOf, null, type);
+
+ if (graph.hasValue(source)) {
+ Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
+ Binding b = Bindings.getBinding(dt);
+ graph.claimValue(copy, graph.getValue(source, b), b);
+ }
+
+ // Copy tags
+ for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
+ if (stm.isAsserted(source))
+ continue;
+ if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\tcopying tag ("
+ + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
+ + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
+ graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
+ }
+ }
+
+ for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
+ Resource relation = stm.getPredicate();
+
+ // InstanceOf statements are handled separately, silently ignore them here.
+ if (L0.InstanceOf.equals(relation))
+ continue;
+
+ // Don't copy asserted relations!
+ if (stm.isAsserted(source)) {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\tskipping asserted statement (" + NameUtils.toString(graph, stm) + ")");
+ continue;
+ }
+
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
+
+ Resource subject = stm.getSubject();
+ Resource inverse = graph.getPossibleInverse(relation);
+ Resource obj = stm.getObject();
+ Resource propType = graph.getPossibleType(obj, L0.Literal);
+ boolean addInverse = false;
+ boolean forceIncludeAndFollow = false;
+
+ switch (evaluate(graph, stm, advisor)) {
+ case SKIP:
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tskipping statement");
+ break;
+
+ case INCLUDE:
+ {
+ // Don't clone the object, just add relation to the same object.
+ if (inverse != null)
+ addInverse = graph.hasStatement(obj, inverse, subject);
+
+ if (DEBUG_COPY) {
+ System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy2.claim(" + NameUtils.getSafeName(graph, copy) + ", "
+ + NameUtils.getSafeName(graph, relation) + ", "
+ + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
+ + NameUtils.getSafeName(graph, obj));
+ }
+
+ graph.claim(copy, relation, addInverse ? inverse : null, obj);
+ break;
+ }
+
+ case INCLUDE_AND_FOLLOW:
+ // Force follow-through in the default copy logic
+ forceIncludeAndFollow = true;
+ // NOTE: intentional fall-through here
+
+ case USE_DEFAULT:
+ {
+ if (forceIncludeAndFollow || propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
+ if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
+ // This logic is applied only for enumeration property
+ // statements that should not have an inverse in any case.
+ if (DEBUG_COPY) {
+ System.out.println("[" + level + "]\t\tclaim enumeration statement("
+ + NameUtils.getSafeName(graph, copy) + ", "
+ + NameUtils.getSafeName(graph, relation)+ ", null, "
+ + NameUtils.getSafeName(graph, obj));
+ }
+ graph.claim(copy, relation, null, obj);
+ } else {
+ // This logic is applied for other properties besides enumerations
+ if (inverse != null)
+ addInverse = graph.hasStatement(obj, inverse, subject);
+
+ String objectURI = graph.getPossibleURI(obj);
+
+ if(objectURI != null && !objectURI.startsWith(modelURI)) {
+
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tclaim ontological reference");
+
+ graph.claim(copy, relation, null, obj);
+
+ } else {
+
+ // Copy instantiated properties, not asserted ones.
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tcopy whole object");
+
+ Resource clone = copy3(graph, modelURI, obj, level + 1, advisor, copyMap);
+ graph.claim(copy, relation, inverse, clone);
+
+ }
+
+ }
+ } else {
+ if (DEBUG_COPY)
+ System.out.println("[" + level + "]\t\tskipping statement");
+ }
+ }
+ }
+ }
+ return copy;
+ }
+
+ protected static StatementEvaluation evaluate(ReadGraph graph, Statement stm, BiFunction tester) {
+ if (tester == null)
+ return StatementEvaluation.USE_DEFAULT;
+ return tester.apply(graph, stm);
+ }
+
+ /**
+ * Equal to
+ * copy4(graph, source, graph.adapt(source, CopyHandler.class)))
+ * .
+ *
+ * @param graph database write access
+ * @param source the resource to start the copy from
+ * @return the copied resource
+ * @throws DatabaseException
+ */
+ public static Resource copy4(WriteGraph graph, Resource source) throws DatabaseException {
+ CopyHandler handler = graph.adapt(source, CopyHandler.class);
+ return copy4(graph, source, handler);
+ }
+
+ /**
+ * Creates and returns a copy of the specified source resource based on
+ * transferable graph export and import. The TG representation shall be
+ * generated by the specified {@link CopyHandler} into a
+ * {@link SimanticsClipboard} instance from where it is read back as
+ * {@link TransferableGraph1} and imported into the database through
+ * {@link TransferableGraphs#importGraph1(WriteGraph, TransferableGraph1, org.simantics.graph.db.IImportAdvisor)}.
+ *
+ * @param graph database write access
+ * @param source the resource to start the copy from
+ * @param copyHandler the handler to use for generating the transferable
+ * graph representation from the copied resource
+ * @return the copied resource
+ * @throws DatabaseException
+ */
+ public static Resource copy4(WriteGraph graph, Resource source, CopyHandler copyHandler) throws DatabaseException {
+ SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
+ copyHandler.copyToClipboard(graph, builder, new NullProgressMonitor());
+
+ for(Set object : builder.getContents()) {
+ TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
+ if(tg != null) {
+ FixedRootImportAdvisor advisor = new FixedRootImportAdvisor();
+ TransferableGraphs.importGraph1(graph, tg, advisor);
+ return advisor.getRoot();
+ }
+ }
+
+ String uri = graph.getPossibleURI(source);
+ throw new DatabaseException("Failed to copy resource " + NameUtils.getSafeName(graph, source, true)
+ + (uri != null ? " with URI " + uri : ""));
+ }
+
+}