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.simantics.databoard.Bindings;
21 import org.simantics.databoard.binding.Binding;
22 import org.simantics.databoard.type.Datatype;
23 import org.simantics.db.ReadGraph;
24 import org.simantics.db.Resource;
25 import org.simantics.db.Statement;
26 import org.simantics.db.WriteGraph;
27 import org.simantics.db.common.utils.NameUtils;
28 import org.simantics.db.exception.DatabaseException;
29 import org.simantics.db.layer0.adapter.CopyHandler;
30 import org.simantics.db.layer0.adapter.impl.FixedRootImportAdvisor;
31 import org.simantics.db.layer0.util.ClipboardUtils;
32 import org.simantics.db.layer0.util.SimanticsClipboard;
33 import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
34 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
35 import org.simantics.db.layer0.util.SimanticsKeys;
36 import org.simantics.diagram.adapter.GraphToDiagramSynchronizer;
37 import org.simantics.diagram.internal.DebugPolicy;
38 import org.simantics.diagram.synchronization.CopyAdvisor;
39 import org.simantics.diagram.synchronization.CopyAdvisor.Evaluation;
40 import org.simantics.diagram.synchronization.ErrorHandler;
41 import org.simantics.diagram.synchronization.IModifiableSynchronizationContext;
42 import org.simantics.diagram.synchronization.StatementEvaluation;
43 import org.simantics.diagram.synchronization.SynchronizationException;
44 import org.simantics.diagram.synchronization.SynchronizationHints;
45 import org.simantics.graph.db.TransferableGraphs;
46 import org.simantics.graph.representation.TransferableGraph1;
47 import org.simantics.layer0.Layer0;
50 * This class contains utility methods for the basic cut/copy operations
51 * performed related to cut-copy-pasting diagram/configuration component and
56 * {@link #cut(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
58 * {@link #copy(IModifiableSynchronizationContext, WriteGraph, CopyAdvisor, Resource, Resource, Resource)}
59 * are available for making it easier to properly invoke
60 * {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
62 * {@link CopyAdvisor#copy(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
63 * operations in a diagram/graph transaction context.
66 * Methods {@link #copy(WriteGraph, Resource, BinaryFunction)},
67 * {@link #copy2(WriteGraph, Resource, BinaryFunction)},
68 * {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)},
69 * {@link #copy4(WriteGraph, Resource)} and
70 * {@link #copy4(WriteGraph, Resource, CopyHandler)} offer differently
71 * functioning versions of copying a single resource in the graph that are
72 * mainly tuned for copying diagram elements and configuration components.
75 * <b>IMPORTANT:</b> Note that copy, copy2 and copy3 cannot handle copying of ordered sets
78 * @author Tuukka Lehtonen
80 public class CopyAdvisorUtil {
82 public static final boolean DEBUG_COPY = DebugPolicy.DEBUG_COPY_PASTE;
85 * @param context a synchronization context instance, such as
86 * {@link GraphToDiagramSynchronizer}
87 * @param g handle for graph writing
88 * @param ca the advisor for the copy operation
89 * @param cut the resource that is about to be cut
90 * @param sourceContainer the container from which the cut argument is about
92 * @param targetContainer the container into which the cut argument is about
94 * @return the result of
95 * {@link CopyAdvisor#cut(org.simantics.diagram.synchronization.ISynchronizationContext, Object, Object, Object)}
96 * @throws DatabaseException
98 public static Object cut(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca, Resource cut, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
100 System.out.println("Attempting to cut component " + NameUtils.getSafeName(g, cut, true));
102 context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
103 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
104 return ca.cut(context, cut, sourceContainer, targetContainer);
105 } catch (SynchronizationException e) {
106 ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
107 eh.error(e.getMessage(), e);
109 context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
110 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
116 * @param context a synchronization context instance, such as
117 * {@link GraphToDiagramSynchronizer}
118 * @param g handle for graph writing
119 * @param ca the advisor for the copy operation
120 * @param copyOf the resource that is about to be copied
121 * @param sourceContainer the container of the resource that will be copied
122 * @param targetContainer the to-be container of the copied resource instance
123 * @return the copied resource
124 * @throws DatabaseException
126 public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
127 Resource copyOf, Resource sourceContainer, Resource targetContainer) throws DatabaseException {
128 Resource resource = null;
130 System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
132 context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
133 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
134 Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
136 System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
137 if (CopyAdvisor.SUPPORTED.contains(eval)) {
138 Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer);
140 System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
141 if (copy instanceof Resource) {
142 resource = (Resource) copy;
144 throw new UnsupportedOperationException("Cannot copy element " + copyOf);
147 } catch (SynchronizationException e) {
148 ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
149 eh.error(e.getMessage(), e);
150 // throwing exception allows canceling failed copy!
151 throw new DatabaseException(e);
153 context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
154 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
160 * @param context a synchronization context instance, such as
161 * {@link GraphToDiagramSynchronizer}
162 * @param g handle for graph writing
163 * @param ca the advisor for the copy operation
164 * @param copyOf the resource that is about to be copied
165 * @param sourceContainer the container of the resource that will be copied
166 * @param targetContainer the to-be container of the copied resource instance
167 * @param map a map for storing the correspondences between original and
168 * copied objects. This is used to output data from the copy process.
169 * @return the copied resource
170 * @throws DatabaseException
172 public static Resource copy(IModifiableSynchronizationContext context, WriteGraph g, CopyAdvisor ca,
173 Resource copyOf, Resource sourceContainer, Resource targetContainer, Map<Object, Object> map)
174 throws DatabaseException {
175 Resource resource = null;
177 System.out.println("Attempting to copy component " + NameUtils.getSafeName(g, copyOf, true));
179 context.set(GraphSynchronizationHints.READ_TRANSACTION, g);
180 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, g);
181 Evaluation eval = ca.canCopy(context, copyOf, sourceContainer, targetContainer);
183 System.out.println(" CopyAdvisor(" + ca + ").canCopy evaluation result: " + eval);
184 if (CopyAdvisor.SUPPORTED.contains(eval)) {
185 Object copy = ca.copy(context, copyOf, sourceContainer, targetContainer, map);
187 System.out.println(" CopyAdvisor(" + ca + ").copy result: " + copy);
188 System.out.println(" CopyAdvisor(" + ca + ").copy result map: " + map);
190 if (copy instanceof Resource) {
191 resource = (Resource) copy;
193 throw new UnsupportedOperationException("Cannot copy element " + copyOf);
196 } catch (SynchronizationException e) {
197 ErrorHandler eh = context.get(SynchronizationHints.ERROR_HANDLER);
198 eh.error(e.getMessage(), e);
199 // throwing exception allows canceling failed copy!
200 throw new DatabaseException(e);
202 context.set(GraphSynchronizationHints.READ_TRANSACTION, null);
203 context.set(GraphSynchronizationHints.WRITE_TRANSACTION, null);
209 * Creates and returns a copy of the specified source resource based on the
210 * standard Layer0 relation hierarchy by recursively including all resources
211 * in the copy that the source and is composed of (see
212 * {@link Layer0#IsComposedOf}). The routine will always copy at least all
213 * L0.InstanceOf statements and tags related to its input resource. If the
214 * copied resource has a value attached, it will also be copied.
216 * @param graph database write access
217 * @param source the resource to start the copy from
218 * @param advisor <code>null</code> or a custom advisor to guide whether or
219 * not to copy relations that are not inherited from L0.IsComposedOf.
220 * This advisor cannot be used to say that non-composing relations
221 * should perform recursive copy, only whether to copy the tested
222 * statement of or not.
223 * @return the copied resource
224 * @throws DatabaseException
226 public static Resource copy(WriteGraph graph, Resource source, BiFunction<ReadGraph, Statement, Boolean> advisor) throws DatabaseException {
227 return copy(graph, source, 0, advisor, new THashMap<Object, Object>());
231 * See {@link #copy(WriteGraph, Resource, BinaryFunction)}.
236 * @param copyMap a map for storing the correspondences between original and
237 * copied objects. This is used to output data from the copy process.
239 * @throws DatabaseException
241 public static Resource copy(WriteGraph graph, Resource source, BiFunction<ReadGraph, Statement, Boolean> advisor, Map<Object, Object> copyMap) throws DatabaseException {
242 return copy(graph, source, 0, advisor, copyMap);
245 private static Resource copy(WriteGraph graph, Resource source, int level, BiFunction<ReadGraph, Statement, Boolean> advisor, Map<Object, Object> copyMap) throws DatabaseException {
247 System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
249 Resource copy = (Resource) copyMap.get(source);
252 System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
256 Layer0 L0 = Layer0.getInstance(graph);
257 copy = graph.newResource();
258 copyMap.put(source, copy);
259 for (Resource type : graph.getObjects(source, L0.InstanceOf))
260 graph.claim(copy, L0.InstanceOf, null, type);
262 if (graph.hasValue(source)) {
263 Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
264 Binding b = Bindings.getBinding(dt);
265 graph.claimValue(copy, graph.<Object>getValue(source, b), b);
269 for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
270 if (stm.isAsserted(source))
272 if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
274 System.out.println("[" + level + "]\tcopying tag ("
275 + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
276 + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
277 graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
281 for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
282 Resource relation = stm.getPredicate();
284 // InstanceOf statements are handled separately, silently ignore them here.
285 if (L0.InstanceOf.equals(relation))
288 // Don't copy asserted relations!
289 if (stm.isAsserted(source)) {
291 System.out.println("[" + level + "]\t\tSkipping asserted statement");
296 System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
298 Resource subject = stm.getSubject();
299 Resource inverse = graph.getPossibleInverse(relation);
300 boolean addInverse = false;
301 Resource obj = stm.getObject();
302 Resource propType = graph.getPossibleType(obj, L0.Literal);
304 // §1 only L0.IsComposedOf and its subrelations can be considered to be copied automatically
306 if (propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
307 if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
309 System.out.println("[" + level + "]\t\tclaim enumeration statement");
310 graph.claim(copy, relation, null, obj);
313 addInverse = graph.hasStatement(obj, inverse, subject);
315 // Copy instantiated properties, not asserted ones.
317 System.out.println("[" + level + "]\t\tcopy whole object");
318 Resource clone = copy(graph, obj, level + 1, advisor, copyMap);
319 graph.claim(copy, relation, clone);
322 if (advisor != null) {
323 Boolean result = advisor.apply(graph, stm);
324 if (Boolean.TRUE.equals(result)) {
325 // Don't clone the object, just add relation to the same object.
327 addInverse = graph.hasStatement(obj, inverse, subject);
330 System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy.claim(" + NameUtils.getSafeName(graph, copy) + ", "
331 + NameUtils.getSafeName(graph, relation) + ", "
332 + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
333 + NameUtils.getSafeName(graph, obj));
336 graph.claim(copy, relation, addInverse ? inverse : null, obj);
340 System.out.println("[" + level + "]\t\tskipping statement");
348 * Creates and returns a copy of the specified source resource based on the
349 * standard Layer0 relation hierarchy by recursively including all resources
350 * in the copy that the source and is composed of (see
351 * {@link Layer0#IsComposedOf}). A customizable advisor function can be used
352 * to guide the copy process. The routine will always copy at least all
353 * L0.InstanceOf statements and tags related to its input resource. If the
354 * copied resource has a value attached, it will also be copied.
356 * @param graph database write access
357 * @param source the resource to start the copy from
358 * @param advisor <code>null</code> or a custom advisor to guide the copy
359 * process according to the specifications of
360 * {@link StatementEvaluation}. Every copied statement besides
361 * L0.InstanceOf and tags will be evaluated by this advisor.
362 * @return the copied resource
363 * @throws DatabaseException
365 public static Resource copy2(WriteGraph graph, Resource source,
366 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor) throws DatabaseException {
367 return copy2(graph, source, 0, advisor, new THashMap<Object, Object>());
371 * See {@link #copy2(WriteGraph, Resource, BinaryFunction)}.
376 * @param copyMap a map for storing the correspondences between original and
377 * copied objects. This is used to output data from the copy process.
379 * @throws DatabaseException
381 public static Resource copy2(WriteGraph graph, Resource source,
382 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor, Map<Object, Object> copyMap)
383 throws DatabaseException {
384 return copy2(graph, source, 0, advisor, copyMap);
387 private static Resource copy2(final WriteGraph graph, final Resource source, final int level,
388 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor, Map<Object, Object> copyMap)
389 throws DatabaseException {
391 System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
393 Resource copy = (Resource) copyMap.get(source);
396 System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
400 Layer0 L0 = Layer0.getInstance(graph);
401 copy = graph.newResource();
402 copyMap.put(source, copy);
403 for (Resource type : graph.getObjects(source, L0.InstanceOf))
404 graph.claim(copy, L0.InstanceOf, null, type);
406 if (graph.hasValue(source)) {
407 Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
408 Binding b = Bindings.getBinding(dt);
409 graph.claimValue(copy, graph.<Object>getValue(source, b), b);
413 for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
414 if (stm.isAsserted(source))
416 if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
418 System.out.println("[" + level + "]\tcopying tag ("
419 + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
420 + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
421 graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
425 for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
426 Resource relation = stm.getPredicate();
428 // InstanceOf statements are handled separately, silently ignore them here.
429 if (L0.InstanceOf.equals(relation))
432 // Don't copy asserted relations!
433 if (stm.isAsserted(source)) {
435 System.out.println("[" + level + "]\tskipping asserted statement (" + NameUtils.toString(graph, stm) + ")");
440 System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
442 Resource subject = stm.getSubject();
443 Resource inverse = graph.getPossibleInverse(relation);
444 Resource obj = stm.getObject();
445 Resource propType = graph.getPossibleType(obj, L0.Literal);
446 boolean addInverse = false;
447 boolean forceIncludeAndFollow = false;
449 switch (evaluate(graph, stm, advisor)) {
452 System.out.println("[" + level + "]\t\tskipping statement");
457 // Don't clone the object, just add relation to the same object.
459 addInverse = graph.hasStatement(obj, inverse, subject);
462 System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy2.claim(" + NameUtils.getSafeName(graph, copy) + ", "
463 + NameUtils.getSafeName(graph, relation) + ", "
464 + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
465 + NameUtils.getSafeName(graph, obj));
468 graph.claim(copy, relation, addInverse ? inverse : null, obj);
472 case INCLUDE_AND_FOLLOW:
473 // Force follow-through in the default copy logic
474 forceIncludeAndFollow = true;
475 // NOTE: intentional fall-through here
479 if (forceIncludeAndFollow || propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
480 if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
481 // This logic is applied only for enumeration property
482 // statements that should not have an inverse in any case.
484 System.out.println("[" + level + "]\t\tclaim enumeration statement("
485 + NameUtils.getSafeName(graph, copy) + ", "
486 + NameUtils.getSafeName(graph, relation)+ ", null, "
487 + NameUtils.getSafeName(graph, obj));
489 graph.claim(copy, relation, null, obj);
491 // This logic is applied for other properties besides enumerations
493 addInverse = graph.hasStatement(obj, inverse, subject);
495 // Copy instantiated properties, not asserted ones.
497 System.out.println("[" + level + "]\t\tcopy whole object");
499 Resource clone = copy2(graph, obj, level + 1, advisor, copyMap);
500 graph.claim(copy, relation, inverse, clone);
504 System.out.println("[" + level + "]\t\tskipping statement");
513 * Creates and returns a copy of the specified source resource based on the
514 * standard Layer0 relation hierarchy by recursively including all resources
515 * in the copy that the source and is composed of (see
516 * {@link Layer0#IsComposedOf}). A customizable advisor function can be used
517 * to guide the copy process. The routine will always copy at least all
518 * L0.InstanceOf statements and tags related to its input resource. If the
519 * copied resource has a value attached, it will also be copied.
521 * Works exactly like {@link #copy2(WriteGraph, Resource, BinaryFunction)}
522 * but uses the <code>model</code> argument to make sure that the copy
523 * process does not propagate outside of the model. Any references that go
524 * to resources with URIs that are not in the model's namespace are copied
527 * @param graph database write access
528 * @param source the resource to start the copy from
529 * @param model the model containing the source object, used to keep the
530 * copy process model-local
531 * @param advisor <code>null</code> or a custom advisor to guide the copy
532 * process according to the specifications of
533 * {@link StatementEvaluation}. Every copied statement besides
534 * L0.InstanceOf and tags will be evaluated by this advisor.
535 * @return the copied resource
536 * @throws DatabaseException
538 public static Resource copy3(WriteGraph graph, Resource source, Resource model,
539 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor) throws DatabaseException {
540 String modelURI = graph.getURI(model);
541 return copy3(graph, modelURI, source, 0, advisor, new THashMap<Object, Object>());
545 * See {@link #copy3(WriteGraph, Resource, Resource, BinaryFunction)}.
551 * @param copyMap a map for storing the correspondences between original and
552 * copied objects. This is used to output data from the copy process.
554 * @throws DatabaseException
556 public static Resource copy3(WriteGraph graph, Resource source, Resource model,
557 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor, Map<Object, Object> copyMap) throws DatabaseException {
558 String modelURI = graph.getURI(model);
559 return copy3(graph, modelURI, source, 0, advisor, copyMap);
562 private static Resource copy3(WriteGraph graph, String modelURI, Resource source, int level,
563 BiFunction<ReadGraph, Statement, StatementEvaluation> advisor, Map<Object, Object> copyMap)
564 throws DatabaseException {
566 System.out.println("[" + level + "] CopyAdvisorUtil.copy(" + NameUtils.getSafeName(graph, source) + ", advisor=" + advisor + ")");
568 Resource copy = (Resource) copyMap.get(source);
571 System.out.println("[" + level + "] already copied: " + NameUtils.getSafeName(graph, source) + " -> " + NameUtils.getSafeName(graph, copy));
575 Layer0 L0 = Layer0.getInstance(graph);
576 copy = graph.newResource();
577 copyMap.put(source, copy);
578 for (Resource type : graph.getObjects(source, L0.InstanceOf))
579 graph.claim(copy, L0.InstanceOf, null, type);
581 if (graph.hasValue(source)) {
582 Datatype dt = graph.getRelatedValue(source, L0.HasDataType, Bindings.getBindingUnchecked(Datatype.class));
583 Binding b = Bindings.getBinding(dt);
584 graph.claimValue(copy, graph.<Object>getValue(source, b), b);
588 for (Statement stm : graph.getStatements(source, L0.IsWeaklyRelatedTo)) {
589 if (stm.isAsserted(source))
591 if (graph.isInstanceOf(stm.getPredicate(), L0.Tag)) {
593 System.out.println("[" + level + "]\tcopying tag ("
594 + NameUtils.getSafeName(graph, stm.getSubject()) + ", "
595 + NameUtils.getSafeName(graph, stm.getPredicate()) + ")");
596 graph.claim(copy, stm.getPredicate(), stm.getPredicate(), copy);
600 for (Statement stm : graph.getStatements(source, L0.IsRelatedTo)) {
601 Resource relation = stm.getPredicate();
603 // InstanceOf statements are handled separately, silently ignore them here.
604 if (L0.InstanceOf.equals(relation))
607 // Don't copy asserted relations!
608 if (stm.isAsserted(source)) {
610 System.out.println("[" + level + "]\tskipping asserted statement (" + NameUtils.toString(graph, stm) + ")");
615 System.out.println("[" + level + "]\tprocessing statement (" + NameUtils.toString(graph, stm) + ")");
617 Resource subject = stm.getSubject();
618 Resource inverse = graph.getPossibleInverse(relation);
619 Resource obj = stm.getObject();
620 Resource propType = graph.getPossibleType(obj, L0.Literal);
621 boolean addInverse = false;
622 boolean forceIncludeAndFollow = false;
624 switch (evaluate(graph, stm, advisor)) {
627 System.out.println("[" + level + "]\t\tskipping statement");
632 // Don't clone the object, just add relation to the same object.
634 addInverse = graph.hasStatement(obj, inverse, subject);
637 System.out.println("[" + level + "]\t\tCopyAdvisorUtil.copy2.claim(" + NameUtils.getSafeName(graph, copy) + ", "
638 + NameUtils.getSafeName(graph, relation) + ", "
639 + (addInverse ? NameUtils.getSafeName(graph, inverse) : null) + ", "
640 + NameUtils.getSafeName(graph, obj));
643 graph.claim(copy, relation, addInverse ? inverse : null, obj);
647 case INCLUDE_AND_FOLLOW:
648 // Force follow-through in the default copy logic
649 forceIncludeAndFollow = true;
650 // NOTE: intentional fall-through here
654 if (forceIncludeAndFollow || propType != null || graph.isSubrelationOf(relation, L0.IsComposedOf)) {
655 if (propType != null && graph.hasStatement(propType, L0.Enumeration, propType)) {
656 // This logic is applied only for enumeration property
657 // statements that should not have an inverse in any case.
659 System.out.println("[" + level + "]\t\tclaim enumeration statement("
660 + NameUtils.getSafeName(graph, copy) + ", "
661 + NameUtils.getSafeName(graph, relation)+ ", null, "
662 + NameUtils.getSafeName(graph, obj));
664 graph.claim(copy, relation, null, obj);
666 // This logic is applied for other properties besides enumerations
668 addInverse = graph.hasStatement(obj, inverse, subject);
670 String objectURI = graph.getPossibleURI(obj);
672 if(objectURI != null && !objectURI.startsWith(modelURI)) {
675 System.out.println("[" + level + "]\t\tclaim ontological reference");
677 graph.claim(copy, relation, null, obj);
681 // Copy instantiated properties, not asserted ones.
683 System.out.println("[" + level + "]\t\tcopy whole object");
685 Resource clone = copy3(graph, modelURI, obj, level + 1, advisor, copyMap);
686 graph.claim(copy, relation, inverse, clone);
693 System.out.println("[" + level + "]\t\tskipping statement");
701 protected static StatementEvaluation evaluate(ReadGraph graph, Statement stm, BiFunction<ReadGraph, Statement, StatementEvaluation> tester) {
703 return StatementEvaluation.USE_DEFAULT;
704 return tester.apply(graph, stm);
709 * <code>copy4(graph, source, graph.adapt(source, CopyHandler.class)))</code>
712 * @param graph database write access
713 * @param source the resource to start the copy from
714 * @return the copied resource
715 * @throws DatabaseException
717 public static Resource copy4(WriteGraph graph, Resource source) throws DatabaseException {
718 CopyHandler handler = graph.adapt(source, CopyHandler.class);
719 return copy4(graph, source, handler);
723 * Creates and returns a copy of the specified source resource based on
724 * transferable graph export and import. The TG representation shall be
725 * generated by the specified {@link CopyHandler} into a
726 * {@link SimanticsClipboard} instance from where it is read back as
727 * {@link TransferableGraph1} and imported into the database through
728 * {@link TransferableGraphs#importGraph1(WriteGraph, TransferableGraph1, org.simantics.graph.db.IImportAdvisor)}.
730 * @param graph database write access
731 * @param source the resource to start the copy from
732 * @param copyHandler the handler to use for generating the transferable
733 * graph representation from the copied resource
734 * @return the copied resource
735 * @throws DatabaseException
737 public static Resource copy4(WriteGraph graph, Resource source, CopyHandler copyHandler) throws DatabaseException {
738 SimanticsClipboardImpl builder = new SimanticsClipboardImpl();
739 copyHandler.copyToClipboard(graph, builder);
741 for(Set<Representation> object : builder.getContents()) {
742 TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
744 FixedRootImportAdvisor advisor = new FixedRootImportAdvisor();
745 TransferableGraphs.importGraph1(graph, tg, advisor);
746 return advisor.getRoot();
750 String uri = graph.getPossibleURI(source);
751 throw new DatabaseException("Failed to copy resource " + NameUtils.getSafeName(graph, source, true)
752 + (uri != null ? " with URI " + uri : ""));