1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.diagram.synchronization.graph;
14 import gnu.trove.map.hash.THashMap;
18 import java.util.function.BiFunction;
20 import org.eclipse.core.runtime.NullProgressMonitor;
21 import org.simantics.databoard.Bindings;
22 import org.simantics.databoard.binding.Binding;
23 import org.simantics.databoard.type.Datatype;
24 import org.simantics.db.ReadGraph;
25 import org.simantics.db.Resource;
26 import org.simantics.db.Statement;
27 import org.simantics.db.WriteGraph;
28 import org.simantics.db.common.utils.NameUtils;
29 import org.simantics.db.exception.DatabaseException;
30 import org.simantics.db.layer0.adapter.CopyHandler;
31 import org.simantics.db.layer0.adapter.impl.FixedRootImportAdvisor;
32 import org.simantics.db.layer0.util.ClipboardUtils;
33 import org.simantics.db.layer0.util.SimanticsClipboard;
34 import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
35 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
36 import org.simantics.db.layer0.util.SimanticsKeys;
37 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
38 import org.simantics.diagram.internal.DebugPolicy;
39 import org.simantics.diagram.synchronization.CopyAdvisor;
40 import org.simantics.diagram.synchronization.CopyAdvisor.Evaluation;
41 import org.simantics.diagram.synchronization.ErrorHandler;
42 import org.simantics.diagram.synchronization.IModifiableSynchronizationContext;
43 import org.simantics.diagram.synchronization.StatementEvaluation;
44 import org.simantics.diagram.synchronization.SynchronizationException;
45 import org.simantics.diagram.synchronization.SynchronizationHints;
46 import org.simantics.graph.db.TransferableGraphs;
47 import org.simantics.graph.representation.TransferableGraph1;
48 import org.simantics.layer0.Layer0;
51 * This class contains utility methods for the basic cut/copy operations
52 * performed related to cut-copy-pasting diagram/configuration component and
57 * {@link #cut(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
59 * {@link #copy(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
60 * are available for making it easier to properly invoke
61 * {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
63 * {@link CopyAdvisor#copy(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
64 * operations in a diagram/graph transaction context.
67 * Methods {@link #copy(WriteGraph, Resource, BinaryFunction)},
68 * {@link #copy2(WriteGraph, Resource, BinaryFunction)},
69 * {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)},
70 * {@link #copy4(WriteGraph, Resource)} and
71 * {@link #copy4(WriteGraph, Resource, CopyHandler)} offer differently
72 * functioning versions of copying a single resource in the graph that are
73 * mainly tuned for copying diagram elements and configuration components.
76 * <b>IMPORTANT:</b> Note that copy, copy2 and copy3 cannot handle copying of ordered sets
79 * @author Tuukka Lehtonen
81 public class CopyAdvisorUtil {
83 public static final boolean DEBUG_COPY = DebugPolicy.DEBUG_COPY_PASTE;
86 * @param context a synchronization context instance, such as
87 * {@link GraphToDiagramSynchronizer}
88 * @param g handle for graph writing
89 * @param ca the advisor for the copy operation
90 * @param cut the resource that is about to be cut
91 * @param sourceContainer the container from which the cut argument is about
93 * @param targetContainer the container into which the cut argument is about
95 * @return the result of
96 * {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
97 * @throws DatabaseException
99 public static Object cut(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca, Resource cut, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
101 System.out.println("Attempting to cut component " + NameUtils.getSafeName(g, cut, true));
103 context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
104 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
105 return ca.cut(context, cut, sourceContainer, targetContainer);
106 } catch (SynchronizationException e) {
107 ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
108 eh.error(e.getMessage(), e);
110 context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
111 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
117 * @param context a synchronization context instance, such as
118 * {@link GraphToDiagramSynchronizer}
119 * @param g handle for graph writing
120 * @param ca the advisor for the copy operation
121 * @param copyOf the resource that is about to be copied
122 * @param sourceContainer the container of the resource that will be copied
123 * @param targetContainer the to-be container of the copied resource instance
124 * @return the copied resource
125 * @throws DatabaseException
127 public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
128 Resource copyOf, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
129 Resource resource = null;
131 System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
133 context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
134 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
135 Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
137 System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
138 if (CopyAdvisor.SUPPORTED.contains(eval)) {
139 Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer);
141 System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
142 if (copy instanceof Resource) {
143 resource = (Resource) copy;
145 throw new UnsupportedOperationException("Cannot copy element " + copyOf);
148 } catch (SynchronizationException e) {
149 ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
150 eh.error(e.getMessage(), e);
151 // throwing exception allows canceling failed copy!
152 throw new DatabaseException(e);
154 context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
155 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
161 * @param context a synchronization context instance, such as
162 * {@link GraphToDiagramSynchronizer}
163 * @param g handle for graph writing
164 * @param ca the advisor for the copy operation
165 * @param copyOf the resource that is about to be copied
166 * @param sourceContainer the container of the resource that will be copied
167 * @param targetContainer the to-be container of the copied resource instance
168 * @param map a map for storing the correspondences between original and
169 * copied objects. This is used to output data from the copy process.
170 * @return the copied resource
171 * @throws DatabaseException
173 public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
174 Resource copyOf, Resource sourceContainer, Resource targetContainer, Map<Object, Object> map)
175 throws DatabaseException {
176 Resource resource = null;
178 System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
180 context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
181 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
182 Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
184 System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
185 if (CopyAdvisor.SUPPORTED.contains(eval)) {
186 Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer, map);
188 System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
189 System.out.println(" CopyAdvisor(" + ca + ").copy result map: " + map);
191 if (copy instanceof Resource) {
192 resource = (Resource) copy;
194 throw new UnsupportedOperationException("Cannot copy element " + copyOf);
197 } catch (SynchronizationException e) {
198 ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
199 eh.error(e.getMessage(), e);
200 // throwing exception allows canceling failed copy!
201 throw new DatabaseException(e);
203 context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
204 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
210 * Creates and returns a copy of the specified source resource based on the
211 * standard Layer0 relation hierarchy by recursively including all resources
212 * in the copy that the source and is composed of (see
213 * {@link Layer0#IsComposedOf}). The routine will always copy at least all
214 * L0.InstanceOf statements and tags related to its input resource. If the
215 * copied resource has a value attached, it will also be copied.
217 * @param graph database write access
218 * @param source the resource to start the copy from
219 * @param advisor <code>null</code> or a custom advisor to guide whether or
220 * not to copy relations that are not inherited from L0.IsComposedOf.
221 * This advisor cannot be used to say that non-composing relations
222 * should perform recursive copy, only whether to copy the tested
223 * statement of or not.
224 * @return the copied resource
225 * @throws DatabaseException
227 public static Resource copy(WriteGraph graph, Resource source, BiFunction<ReadGraph, Statement, Boolean> advisor) throws DatabaseException {
228 return copy(graph, source, 0, advisor, new THashMap<Object, Object>());
232 * See {@link #copy(WriteGraph, Resource, BinaryFunction)}.
237 * @param copyMap a map for storing the correspondences between original and
238 * copied objects. This is used to output data from the copy process.
240 * @throws DatabaseException
242 public static Resource copy(WriteGraph graph, Resource source, BiFunction<ReadGraph, Statement, Boolean> advisor, Map<Object, Object> copyMap) throws DatabaseException {
243 return copy(graph, source, 0, advisor, copyMap);
246 private static Resource copy(WriteGraph graph, Resource source, int level, BiFunction<ReadGraph, Statement, Boolean> advisor, Map<Object, Object> copyMap) throws DatabaseException {
248 System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
250 Resource copy = (Resource) copyMap.get(source);
253 System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
257 Layer0 L0 = Layer0.getInstance(graph);
258 copy = graph.newResource();
259 copyMap.put(source, copy);
260 for (Resource type : graph.getObjects(source, L0.InstanceOf))
261 graph.claim(copy, L0.InstanceOf, null, type);
263 if (graph.hasValue(source)) {
264 Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
265 Binding b = Bindings.getBinding(dt);
266 graph.claimValue(copy, graph.<Object>getValue(source, b), b);
270 for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
271 if (stm.isAsserted(source))
273 if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
275 System.out.println("[" + level + "]\tcopying tag ("
276 + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
277 + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
278 graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
282 for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
283 Resource relation = stm.getPredicate();
285 // InstanceOf statements are handled separately, silently ignore them here.
286 if (L0.InstanceOf.equals(relation))
289 // Don't copy asserted relations!
290 if (stm.isAsserted(source)) {
292 System.out.println("[" + level + "]\t\tSkipping asserted statement");
297 System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
299 Resource subject = stm.getSubject();
300 Resource inverse = graph.getPossibleInverse(relation);
301 boolean addInverse = false;
302 Resource obj = stm.getObject();
303 Resource propType = graph.getPossibleType(obj, L0.Literal);
305 // §1 only L0.IsComposedOf and its subrelations can be considered to be copied automatically
307 if (propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
308 if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
310 System.out.println("[" + level + "]\t\tclaim enumeration statement");
311 graph.claim(copy, relation, null, obj);
314 addInverse = graph.hasStatement(obj, inverse, subject);
316 // Copy instantiated properties, not asserted ones.
318 System.out.println("[" + level + "]\t\tcopy whole object");
319 Resource clone = copy(graph, obj, level + 1, advisor, copyMap);
320 graph.claim(copy, relation, clone);
323 if (advisor != null) {
324 Boolean result = advisor.apply(graph, stm);
325 if (Boolean.TRUE.equals(result)) {
326 // Don't clone the object, just add relation to the same object.
328 addInverse = graph.hasStatement(obj, inverse, subject);
331 System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy.claim(" + NameUtils.getSafeName(graph, copy) + ", "
332 + NameUtils.getSafeName(graph, relation) + ", "
333 + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
334 + NameUtils.getSafeName(graph, obj));
337 graph.claim(copy, relation, addInverse ? inverse : null, obj);
341 System.out.println("[" + level + "]\t\tskipping statement");
349 * Creates and returns a copy of the specified source resource based on the
350 * standard Layer0 relation hierarchy by recursively including all resources
351 * in the copy that the source and is composed of (see
352 * {@link Layer0#IsComposedOf}). A customizable advisor function can be used
353 * to guide the copy process. The routine will always copy at least all
354 * L0.InstanceOf statements and tags related to its input resource. If the
355 * copied resource has a value attached, it will also be copied.
357 * @param graph database write access
358 * @param source the resource to start the copy from
359 * @param advisor <code>null</code> or a custom advisor to guide the copy
360 * process according to the specifications of
361 * {@link StatementEvaluation}. Every copied statement besides
362 * L0.InstanceOf and tags will be evaluated by this advisor.
363 * @return the copied resource
364 * @throws DatabaseException
366 public static Resource copy2(WriteGraph graph, Resource source,
367 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor) throws DatabaseException {
368 return copy2(graph, source, 0, advisor, new THashMap<Object, Object>());
372 * See {@link #copy2(WriteGraph, Resource, BinaryFunction)}.
377 * @param copyMap a map for storing the correspondences between original and
378 * copied objects. This is used to output data from the copy process.
380 * @throws DatabaseException
382 public static Resource copy2(WriteGraph graph, Resource source,
383 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor, Map<Object, Object> copyMap)
384 throws DatabaseException {
385 return copy2(graph, source, 0, advisor, copyMap);
388 private static Resource copy2(final WriteGraph graph, final Resource source, final int level,
389 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor, Map<Object, Object> copyMap)
390 throws DatabaseException {
392 System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
394 Resource copy = (Resource) copyMap.get(source);
397 System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
401 Layer0 L0 = Layer0.getInstance(graph);
402 copy = graph.newResource();
403 copyMap.put(source, copy);
404 for (Resource type : graph.getObjects(source, L0.InstanceOf))
405 graph.claim(copy, L0.InstanceOf, null, type);
407 if (graph.hasValue(source)) {
408 Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
409 Binding b = Bindings.getBinding(dt);
410 graph.claimValue(copy, graph.<Object>getValue(source, b), b);
414 for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
415 if (stm.isAsserted(source))
417 if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
419 System.out.println("[" + level + "]\tcopying tag ("
420 + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
421 + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
422 graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
426 for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
427 Resource relation = stm.getPredicate();
429 // InstanceOf statements are handled separately, silently ignore them here.
430 if (L0.InstanceOf.equals(relation))
433 // Don't copy asserted relations!
434 if (stm.isAsserted(source)) {
436 System.out.println("[" + level + "]\tskipping asserted statement (" + NameUtils.toString(graph, stm) + ")");
441 System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
443 Resource subject = stm.getSubject();
444 Resource inverse = graph.getPossibleInverse(relation);
445 Resource obj = stm.getObject();
446 Resource propType = graph.getPossibleType(obj, L0.Literal);
447 boolean addInverse = false;
448 boolean forceIncludeAndFollow = false;
450 switch (evaluate(graph, stm, advisor)) {
453 System.out.println("[" + level + "]\t\tskipping statement");
458 // Don't clone the object, just add relation to the same object.
460 addInverse = graph.hasStatement(obj, inverse, subject);
463 System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy2.claim(" + NameUtils.getSafeName(graph, copy) + ", "
464 + NameUtils.getSafeName(graph, relation) + ", "
465 + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
466 + NameUtils.getSafeName(graph, obj));
469 graph.claim(copy, relation, addInverse ? inverse : null, obj);
473 case INCLUDE_AND_FOLLOW:
474 // Force follow-through in the default copy logic
475 forceIncludeAndFollow = true;
476 // NOTE: intentional fall-through here
480 if (forceIncludeAndFollow || propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
481 if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
482 // This logic is applied only for enumeration property
483 // statements that should not have an inverse in any case.
485 System.out.println("[" + level + "]\t\tclaim enumeration statement("
486 + NameUtils.getSafeName(graph, copy) + ", "
487 + NameUtils.getSafeName(graph, relation)+ ", null, "
488 + NameUtils.getSafeName(graph, obj));
490 graph.claim(copy, relation, null, obj);
492 // This logic is applied for other properties besides enumerations
494 addInverse = graph.hasStatement(obj, inverse, subject);
496 // Copy instantiated properties, not asserted ones.
498 System.out.println("[" + level + "]\t\tcopy whole object");
500 Resource clone = copy2(graph, obj, level + 1, advisor, copyMap);
501 graph.claim(copy, relation, inverse, clone);
505 System.out.println("[" + level + "]\t\tskipping statement");
514 * Creates and returns a copy of the specified source resource based on the
515 * standard Layer0 relation hierarchy by recursively including all resources
516 * in the copy that the source and is composed of (see
517 * {@link Layer0#IsComposedOf}). A customizable advisor function can be used
518 * to guide the copy process. The routine will always copy at least all
519 * L0.InstanceOf statements and tags related to its input resource. If the
520 * copied resource has a value attached, it will also be copied.
522 * Works exactly like {@link #copy2(WriteGraph, Resource, BinaryFunction)}
523 * but uses the <code>model</code> argument to make sure that the copy
524 * process does not propagate outside of the model. Any references that go
525 * to resources with URIs that are not in the model's namespace are copied
528 * @param graph database write access
529 * @param source the resource to start the copy from
530 * @param model the model containing the source object, used to keep the
531 * copy process model-local
532 * @param advisor <code>null</code> or a custom advisor to guide the copy
533 * process according to the specifications of
534 * {@link StatementEvaluation}. Every copied statement besides
535 * L0.InstanceOf and tags will be evaluated by this advisor.
536 * @return the copied resource
537 * @throws DatabaseException
539 public static Resource copy3(WriteGraph graph, Resource source, Resource model,
540 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor) throws DatabaseException {
541 String modelURI = graph.getURI(model);
542 return copy3(graph, modelURI, source, 0, advisor, new THashMap<Object, Object>());
546 * See {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)}.
552 * @param copyMap a map for storing the correspondences between original and
553 * copied objects. This is used to output data from the copy process.
555 * @throws DatabaseException
557 public static Resource copy3(WriteGraph graph, Resource source, Resource model,
558 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor, Map<Object, Object> copyMap) throws DatabaseException {
559 String modelURI = graph.getURI(model);
560 return copy3(graph, modelURI, source, 0, advisor, copyMap);
563 private static Resource copy3(WriteGraph graph, String modelURI, Resource source, int level,
564 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor, Map<Object, Object> copyMap)
565 throws DatabaseException {
567 System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
569 Resource copy = (Resource) copyMap.get(source);
572 System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
576 Layer0 L0 = Layer0.getInstance(graph);
577 copy = graph.newResource();
578 copyMap.put(source, copy);
579 for (Resource type : graph.getObjects(source, L0.InstanceOf))
580 graph.claim(copy, L0.InstanceOf, null, type);
582 if (graph.hasValue(source)) {
583 Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
584 Binding b = Bindings.getBinding(dt);
585 graph.claimValue(copy, graph.<Object>getValue(source, b), b);
589 for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
590 if (stm.isAsserted(source))
592 if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
594 System.out.println("[" + level + "]\tcopying tag ("
595 + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
596 + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
597 graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
601 for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
602 Resource relation = stm.getPredicate();
604 // InstanceOf statements are handled separately, silently ignore them here.
605 if (L0.InstanceOf.equals(relation))
608 // Don't copy asserted relations!
609 if (stm.isAsserted(source)) {
611 System.out.println("[" + level + "]\tskipping asserted statement (" + NameUtils.toString(graph, stm) + ")");
616 System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
618 Resource subject = stm.getSubject();
619 Resource inverse = graph.getPossibleInverse(relation);
620 Resource obj = stm.getObject();
621 Resource propType = graph.getPossibleType(obj, L0.Literal);
622 boolean addInverse = false;
623 boolean forceIncludeAndFollow = false;
625 switch (evaluate(graph, stm, advisor)) {
628 System.out.println("[" + level + "]\t\tskipping statement");
633 // Don't clone the object, just add relation to the same object.
635 addInverse = graph.hasStatement(obj, inverse, subject);
638 System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy2.claim(" + NameUtils.getSafeName(graph, copy) + ", "
639 + NameUtils.getSafeName(graph, relation) + ", "
640 + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
641 + NameUtils.getSafeName(graph, obj));
644 graph.claim(copy, relation, addInverse ? inverse : null, obj);
648 case INCLUDE_AND_FOLLOW:
649 // Force follow-through in the default copy logic
650 forceIncludeAndFollow = true;
651 // NOTE: intentional fall-through here
655 if (forceIncludeAndFollow || propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
656 if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
657 // This logic is applied only for enumeration property
658 // statements that should not have an inverse in any case.
660 System.out.println("[" + level + "]\t\tclaim enumeration statement("
661 + NameUtils.getSafeName(graph, copy) + ", "
662 + NameUtils.getSafeName(graph, relation)+ ", null, "
663 + NameUtils.getSafeName(graph, obj));
665 graph.claim(copy, relation, null, obj);
667 // This logic is applied for other properties besides enumerations
669 addInverse = graph.hasStatement(obj, inverse, subject);
671 String objectURI = graph.getPossibleURI(obj);
673 if(objectURI != null && !objectURI.startsWith(modelURI)) {
676 System.out.println("[" + level + "]\t\tclaim ontological reference");
678 graph.claim(copy, relation, null, obj);
682 // Copy instantiated properties, not asserted ones.
684 System.out.println("[" + level + "]\t\tcopy whole object");
686 Resource clone = copy3(graph, modelURI, obj, level + 1, advisor, copyMap);
687 graph.claim(copy, relation, inverse, clone);
694 System.out.println("[" + level + "]\t\tskipping statement");
702 protected static StatementEvaluation evaluate(ReadGraph graph, Statement stm, BiFunction<ReadGraph, Statement, StatementEvaluation> tester) {
704 return StatementEvaluation.USE_DEFAULT;
705 return tester.apply(graph, stm);
710 * <code>copy4(graph, source, graph.adapt(source, CopyHandler.class)))</code>
713 * @param graph database write access
714 * @param source the resource to start the copy from
715 * @return the copied resource
716 * @throws DatabaseException
718 public static Resource copy4(WriteGraph graph, Resource source) throws DatabaseException {
719 CopyHandler handler = graph.adapt(source, CopyHandler.class);
720 return copy4(graph, source, handler);
724 * Creates and returns a copy of the specified source resource based on
725 * transferable graph export and import. The TG representation shall be
726 * generated by the specified {@link CopyHandler} into a
727 * {@link SimanticsClipboard} instance from where it is read back as
728 * {@link TransferableGraph1} and imported into the database through
729 * {@link TransferableGraphs#importGraph1(WriteGraph, TransferableGraph1, org.simantics.graph.db.IImportAdvisor)}.
731 * @param graph database write access
732 * @param source the resource to start the copy from
733 * @param copyHandler the handler to use for generating the transferable
734 * graph representation from the copied resource
735 * @return the copied resource
736 * @throws DatabaseException
738 public static Resource copy4(WriteGraph graph, Resource source, CopyHandler copyHandler) throws DatabaseException {
739 SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
740 copyHandler.copyToClipboard(graph, builder, new NullProgressMonitor());
742 for(Set<Representation> object : builder.getContents()) {
743 TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
745 FixedRootImportAdvisor advisor = new FixedRootImportAdvisor();
746 TransferableGraphs.importGraph1(graph, tg, advisor);
747 return advisor.getRoot();
751 String uri = graph.getPossibleURI(source);
752 throw new DatabaseException("Failed to copy resource " + NameUtils.getSafeName(graph, source, true)
753 + (uri != null ? " with URI " + uri : ""));