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