]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/TypicalUtil.java
a92d7b62643d713ac3095f1d7df58966e8cb80f2
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / typicals / TypicalUtil.java
1 /*******************************************************************************
2  * Copyright (c) 2012 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.modeling.typicals;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.concurrent.Semaphore;
21 import java.util.concurrent.atomic.AtomicReference;
22 import java.util.function.Consumer;
23
24 import org.simantics.NameLabelMode;
25 import org.simantics.NameLabelUtil;
26 import org.simantics.Simantics;
27 import org.simantics.databoard.Bindings;
28 import org.simantics.db.ReadGraph;
29 import org.simantics.db.RequestProcessor;
30 import org.simantics.db.Resource;
31 import org.simantics.db.WriteGraph;
32 import org.simantics.db.WriteOnlyGraph;
33 import org.simantics.db.common.CommentMetadata;
34 import org.simantics.db.common.NamedResource;
35 import org.simantics.db.common.request.FreshName;
36 import org.simantics.db.common.request.ObjectsWithType;
37 import org.simantics.db.common.request.PossibleIndexRoot;
38 import org.simantics.db.common.request.UniqueRead;
39 import org.simantics.db.common.request.WriteResultRequest;
40 import org.simantics.db.common.uri.UnescapedChildMapOfResource;
41 import org.simantics.db.common.utils.CommonDBUtils;
42 import org.simantics.db.common.utils.NameUtils;
43 import org.simantics.db.exception.DatabaseException;
44 import org.simantics.db.exception.RuntimeDatabaseException;
45 import org.simantics.db.layer0.adapter.CopyHandler;
46 import org.simantics.db.layer0.adapter.Instances;
47 import org.simantics.db.layer0.request.Configuration;
48 import org.simantics.db.layer0.request.PossibleModel;
49 import org.simantics.db.layer0.util.ClipboardUtils;
50 import org.simantics.db.layer0.util.SimanticsClipboard.Representation;
51 import org.simantics.db.layer0.util.SimanticsClipboardImpl;
52 import org.simantics.db.layer0.util.SimanticsKeys;
53 import org.simantics.db.layer0.variable.Variable;
54 import org.simantics.db.layer0.variable.Variables;
55 import org.simantics.db.procedure.Procedure;
56 import org.simantics.db.request.WriteResult;
57 import org.simantics.diagram.stubs.DiagramResource;
58 import org.simantics.graph.db.IImportAdvisor;
59 import org.simantics.graph.db.TransferableGraphs;
60 import org.simantics.graph.representation.Root;
61 import org.simantics.graph.representation.TransferableGraph1;
62 import org.simantics.layer0.Layer0;
63 import org.simantics.modeling.ModelingResources;
64 import org.simantics.modeling.ModelingUtils.CompositeInfo;
65 import org.simantics.modeling.ModelingUtils.DiagramComponentInfo;
66 import org.simantics.modeling.services.ComponentNamingUtil;
67 import org.simantics.modeling.services.NamingException;
68 import org.simantics.operation.Layer0X;
69 import org.simantics.scl.runtime.function.Function2;
70 import org.simantics.scl.runtime.function.Function4;
71 import org.simantics.structural.stubs.StructuralResource2;
72 import org.simantics.structural2.utils.StructuralUtils;
73 import org.simantics.ui.SimanticsUI;
74 import org.simantics.utils.datastructures.Pair;
75 import org.simantics.utils.ui.dialogs.ShowMessage;
76
77 /**
78  * @author Tuukka Lehtonen
79  */
80 public class TypicalUtil {
81
82     private static final boolean DEBUG = false;
83
84     private static class TypicalNamingFunction implements Function2<ReadGraph, Resource, String> {
85         private NameLabelMode mode;
86
87         @Override
88         public String apply(ReadGraph graph, Resource r) {
89             try {
90                 if (mode == null)
91                     mode = NameLabelUtil.getNameLabelMode(graph);
92                 Variable v = Variables.getPossibleVariable(graph, r);
93                 if (v != null) {
94                     Resource root = Variables.getPossibleIndexRoot(graph, v);
95                     if (root != null) {
96                         Variable rootV = Variables.getVariable(graph, root);
97                         List<Variable> path = Variables.getPath(graph, rootV, v);
98                         path.add(0, rootV);
99                         return typicalLabel(graph, v, path);
100                     }
101                 }
102                 return TypicalUtil.getName(graph, r);
103             } catch (DatabaseException e) {
104                 throw new RuntimeDatabaseException(e);
105             }
106         }
107
108         protected String typicalLabel(ReadGraph graph, Variable v, List<Variable> path) throws DatabaseException {
109             StringBuilder sb = new StringBuilder();
110             labelVariable(graph, v, sb);
111             if (path.size() > 0) {
112                 sb.append(" (");
113                 for (Variable vv : path) {
114                     sb.append("/");
115                     labelVariable(graph, vv, sb);
116                 }
117                 sb.append(")");
118             }
119             return sb.toString();
120         }
121
122         protected StringBuilder labelVariable(ReadGraph graph, Variable v, StringBuilder result) throws DatabaseException {
123             Resource r = v.getPossibleRepresents(graph);
124             if (r != null) {
125                 result.append(NameLabelUtil.modalName(graph, r, mode));
126             } else {
127                 result.append(NameLabelUtil.modalName(graph, v, mode));
128             }
129             return result;
130         }
131     };
132
133     public static List<NamedResource> toNamedResources(RequestProcessor processor, final Collection<Resource> rs) throws DatabaseException {
134         return toNamedResources(processor, rs, new TypicalNamingFunction());
135     }
136
137     public static List<NamedResource> toNamedResources(RequestProcessor processor, final Collection<Resource> rs, final Function2<ReadGraph, Resource, String> namingFunction) throws DatabaseException {
138         return processor.syncRequest(new UniqueRead<List<NamedResource>>() {
139             @Override
140             public List<NamedResource> perform(ReadGraph graph) throws DatabaseException {
141                 return toNamedResources(graph, rs, namingFunction);
142             }
143         });
144     }
145
146     public static List<NamedResource> toNamedResources(ReadGraph graph, Collection<Resource> rs, final Function2<ReadGraph, Resource, String> namingFunction) throws DatabaseException {
147         List<NamedResource> result = new ArrayList<>(rs.size());
148         for (Resource r : rs)
149             result.add(new NamedResource(namingFunction.apply(graph, r), r));
150         return result;
151     }
152
153     public static String getName(ReadGraph graph, Resource r) throws DatabaseException {
154         String s = graph.getPossibleAdapter(r, String.class);
155         if (s == null)
156             s = NameUtils.getSafeLabel(graph, r);
157         return s;
158     }
159
160     public static WriteResult<Resource> instantiateTemplate(
161             Resource target,
162             NamedResource template,
163             Consumer<Pair<WriteGraph, Resource>> successContinuation)
164     {
165         return new WriteResultRequest<Resource>() {
166             @Override
167             public Resource perform(WriteGraph graph) throws DatabaseException {
168                 // Custom instantiation by copying the original and mapping the original to the copy
169                 CommonDBUtils.selectClusterSet(graph, target);
170                 SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();
171                 CopyHandler ch = new TypicalCompositeCopyHandler(template.getResource());
172                 ch.copyToClipboard(graph, clipboard);
173
174                 Map<String,Object> hints = Collections.singletonMap(ClipboardUtils.HINT_TARGET_RESOURCE, target);
175
176                 for (Set<Representation> object : clipboard.getContents()) {
177                     TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH, hints);
178                     if (tg != null) {
179                         DiagramPasteImportAdvisor advisor = new DiagramPasteImportAdvisor(graph, target, template.getName());
180                         TransferableGraphs.importGraph1(graph, tg, advisor);
181                         Resource copy = advisor.getRoot();
182
183                         configureCopyType(graph, copy, template.getResource());
184                         associateCopyToTemplate(graph, copy, template.getResource());
185
186                         if (successContinuation!= null)
187                             successContinuation.accept(Pair.make(graph, copy));
188
189                         return copy;
190                     }
191                 }
192                 throw new DatabaseException("Failed to instantiate typical template through clipboard");
193             }
194         };
195     }
196
197     public static void configureCopyType(WriteGraph graph, Resource copy, Resource template) throws DatabaseException {
198         // Remove master template instance tag type(s)
199         Layer0 L0 = Layer0.getInstance(graph);
200         DiagramResource DIA = DiagramResource.getInstance(graph);
201         ModelingResources MOD = ModelingResources.getInstance(graph);
202         for (Resource type : graph.getObjects(template, L0.InstanceOf)) {
203             if (graph.isInheritedFrom(type, MOD.MasterTypicalCompositeType))
204                 graph.deny(copy, L0.InstanceOf, type);
205             else
206                 graph.claim(copy, L0.InstanceOf, null, type);
207         }
208         for (Resource templateDiagram : graph.getObjects(template, MOD.CompositeToDiagram)) {
209             Resource templateDiagramType = graph.getPossibleType(templateDiagram, DIA.Diagram);
210             if (templateDiagramType != null) {
211                 for (Resource copiedDiagram : graph.getObjects(copy, MOD.CompositeToDiagram)) {
212                     graph.claim(copiedDiagram, L0.InstanceOf, null, templateDiagramType);
213                 }
214             }
215         }
216     }
217
218     public static void associateCopyToTemplate(WriteGraph graph, Resource copy, Resource template) throws DatabaseException {
219         DiagramResource DIA = DiagramResource.getInstance(graph);
220         ModelingResources MOD = ModelingResources.getInstance(graph);
221         Resource templateDiagram = graph.getSingleObject(template, MOD.CompositeToDiagram);
222         Resource copyDiagram = graph.getSingleObject(copy, MOD.CompositeToDiagram);
223         Map<String, Resource> templateDiagramElements = graph.syncRequest(new UnescapedChildMapOfResource(templateDiagram));
224         Map<String, Resource> copyDiagramElements = graph.syncRequest(new UnescapedChildMapOfResource(copyDiagram));
225
226         // Associations are intentionally bi-directional
227         graph.claim(copyDiagram, MOD.HasDiagramSource, MOD.DiagramHasInstance, templateDiagram);
228         for (String element : templateDiagramElements.keySet()) {
229             Resource templateElement = templateDiagramElements.get(element);
230             if (!graph.isInstanceOf(templateElement, DIA.Element))
231                 continue;
232             Resource copyElement = copyDiagramElements.get(element);
233             graph.claim(copyElement, MOD.HasElementSource, MOD.ElementHasInstance, templateElement);
234             graph.claim(copyElement, MOD.IsTemplatized, MOD.IsTemplatized, copyElement);
235         }
236
237         Long modCount = graph.getPossibleRelatedValue(copyDiagram, DIA.HasModCount);
238         if (modCount == null)
239             modCount = 0L;
240         modCount += 1L << 32;
241         graph.claimLiteral(copyDiagram, DiagramResource.getInstance(graph).HasModCount, modCount, Bindings.LONG);
242     }
243
244     /**
245      * @param graph
246      * @param typicalCompositeInstance
247      * @param excludedComponents the set of components in the specified
248      *        composite that are not freshly renamed or <code>null</code> to
249      *        freshly name all components
250      * @throws DatabaseException
251      */
252     public static void generateFreshModuleNames(WriteGraph graph, Resource typicalCompositeInstance, Set<Resource> excludedComponents) throws DatabaseException {
253         Layer0 L0 = Layer0.getInstance(graph);
254         StructuralResource2 STR = StructuralResource2.getInstance(graph);
255         Resource configurationRoot = graph.sync(new Configuration(typicalCompositeInstance));
256         for(Map.Entry<String, Resource> entry : graph.syncRequest(new UnescapedChildMapOfResource(typicalCompositeInstance)).entrySet()) {
257             Resource component = entry.getValue();
258             if (!graph.isInstanceOf(component, STR.Component))
259                 continue;
260             if (excludedComponents != null && excludedComponents.contains(component))
261                 continue;
262             try {
263                 String renamed = ComponentNamingUtil.findFreshInstanceName(graph, Simantics.getProject(), configurationRoot, typicalCompositeInstance, component);
264                 if (DEBUG)
265                     System.out.println("Typicals: renamed " + entry.getKey() + " -> " + renamed);
266                 graph.claimLiteral(entry.getValue(), L0.HasName, L0.NameOf, renamed, Bindings.STRING);
267             } catch (NamingException e) {
268                 throw new DatabaseException(e);
269             }
270         }
271     }
272
273     public static class DiagramPasteImportAdvisor implements IImportAdvisor {
274
275         protected final Resource library;
276         protected final Resource model;
277         protected Resource diagram;
278         protected final String diagramName;
279
280         public DiagramPasteImportAdvisor(ReadGraph graph, Resource library, String originalName) throws DatabaseException {
281             this.library = library;
282             this.diagram = null;
283             this.diagramName = graph.syncRequest(new FreshName(library, originalName));
284             this.model = graph.syncRequest(new PossibleModel(library));
285         }
286
287         public void analyzeType(ReadGraph graph, Root root) throws DatabaseException {
288         }
289
290         @Override
291         public Resource analyzeRoot(ReadGraph graph, Root root) throws DatabaseException {
292                 if("%model".equals(root.name)) return model;
293                 return null;
294         }
295         @Override
296         public Resource createRoot(WriteOnlyGraph graph, Root root) throws DatabaseException {
297
298                 Layer0 l0 = graph.getService(Layer0.class);
299             if(CompositeInfo.isComposite(root.name)) {
300                 // Use existing if available
301                 if(diagram == null) diagram = graph.newResource();
302                 graph.claim(library, l0.ConsistsOf, l0.PartOf, diagram);
303                 graph.newClusterSet(diagram);
304                 graph.setClusterSet4NewResource(diagram);
305                 graph.addLiteral(diagram, l0.HasName, l0.NameOf, l0.String, diagramName, Bindings.STRING);
306                 return diagram;
307             } else if (DiagramComponentInfo.isDiagramComponent(root.name)) {
308                 DiagramComponentInfo info = DiagramComponentInfo.parse(root.name);
309                 Resource child = graph.newResource();
310                 graph.addLiteral(child, l0.HasName, l0.NameOf, l0.String, info.getUnescapedComponentName(), Bindings.STRING);
311                 return child;
312             } else {
313                 throw new DatabaseException("Unclassified root " + root.name);
314             }
315
316         }
317
318         public Resource getRoot() {
319             return diagram;
320         }
321
322     }
323
324     /**
325      * @param graph
326      * @param typicalInstanceComposite
327      * @param renamedComponentsOutput a set that can be provided to get the set
328      *        of components that was renamed as output from this method or
329      *        <code>null</code> to not collect renamed components
330      * @throws DatabaseException
331      */
332     public static void applyTypicalModuleNames(WriteGraph graph, Resource typicalInstanceComposite, Set<Resource> renamedComponentsOutput) throws DatabaseException {
333         
334         Layer0 L0 = Layer0.getInstance(graph);
335         StructuralResource2 STR = StructuralResource2.getInstance(graph); 
336
337         Function4<ReadGraph, Resource, Resource, String, String> nameEvaluator = getTypicalNamingFunction(graph, typicalInstanceComposite);
338         if (nameEvaluator == null)
339             return;
340
341         Collection<Resource> components = graph.syncRequest(new ObjectsWithType(typicalInstanceComposite, L0.ConsistsOf, STR.Component));
342         for (Resource component : components) {
343                 applyTypicalModuleName(graph, component, nameEvaluator, renamedComponentsOutput);  
344         }
345         
346     }
347
348     public static boolean applyTypicalModuleName(WriteGraph graph, Resource instanceComponent, Function4<ReadGraph, Resource, Resource, String, String> nameEvaluator, Set<Resource> renamedComponentsOutput) throws DatabaseException {
349
350         Layer0 L0 = Layer0.getInstance(graph);
351         StructuralResource2 STR = StructuralResource2.getInstance(graph); 
352         ModelingResources MOD = ModelingResources.getInstance(graph);
353
354         Resource componentType = graph.getPossibleType(instanceComponent, STR.Component);
355         if (componentType == null)
356             return false;
357
358         Resource instanceElement = graph.getPossibleObject(instanceComponent, MOD.ComponentToElement);
359         if (instanceElement == null)
360             return false;
361
362         Resource templateElement = graph.getPossibleObject(instanceElement, MOD.HasElementSource);
363         if (templateElement == null)
364             return false;
365
366         Resource templateComponent = graph.getPossibleObject(templateElement, MOD.ElementToComponent);
367         if (templateComponent == null)
368             return false;
369
370         // TODO: Use variables and EXPRESSION property instead ?
371         String nameExpression = graph.getPossibleRelatedValue(templateComponent, L0.HasName, Bindings.STRING);
372         if (nameExpression == null)
373             return false;
374
375         Resource instanceComposite = graph.getPossibleObject(instanceComponent, L0.PartOf);
376         if (instanceComposite == null)
377             return false;
378         
379         // This evaluator replaces % with assigned primary position name
380         String evaluatedInstanceName = (String) nameEvaluator.apply(graph, instanceComposite, instanceComponent, nameExpression);
381         if(evaluatedInstanceName == null)
382                 return false;
383
384         String instanceName = graph.getPossibleRelatedValue(instanceComponent, L0.HasName, Bindings.STRING);
385         if(instanceName == null)
386                 return false;
387
388         if(!evaluatedInstanceName.equals(instanceName)) {
389                 
390             graph.claimLiteral(instanceComponent, L0.HasName, evaluatedInstanceName, Bindings.STRING);
391             if (renamedComponentsOutput != null)
392                 renamedComponentsOutput.add(instanceComponent);
393             
394             if (DEBUG)
395                 System.out.println("TypicalUtil.applyTypicalModuleName: applied name expression " + nameExpression + " -> " + instanceName + " -> " + evaluatedInstanceName);
396             
397             return true;
398                 
399         }
400         
401         return false;
402         
403     }
404     
405     /**
406      * @param graph
407      * @param typicalComposite
408      * @param componentsToCheck the set of components to check for required
409      *        naming
410      * @throws DatabaseException
411      */
412     public static void applySelectedModuleNames(WriteGraph graph, Resource typicalComposite, List<Resource> componentsToCheck) throws DatabaseException {
413         Layer0 L0 = Layer0.getInstance(graph);
414         StructuralResource2 STR = StructuralResource2.getInstance(graph); 
415         ModelingResources MOD = ModelingResources.getInstance(graph);
416
417         Function4<ReadGraph, Resource, Resource, String, String> nameEvaluator = getTypicalNamingFunction(graph, typicalComposite);
418         if (nameEvaluator == null)
419             return;
420
421         for (Resource component : componentsToCheck) {
422             Resource componentType = graph.getPossibleType(component, STR.Component);
423             if (componentType == null)
424                 continue;
425
426             Resource element = graph.getPossibleObject(component, MOD.ComponentToElement);
427             if (element == null)
428                 continue;
429
430             Resource templateElement = graph.getPossibleObject(element, MOD.HasElementSource);
431             if (templateElement == null)
432                 continue;
433
434             Resource templateComponent = graph.getPossibleObject(templateElement, MOD.ElementToComponent);
435             if (templateComponent == null)
436                 continue;
437
438             String nameExpression = graph.getPossibleRelatedValue(templateComponent, L0.HasName, Bindings.STRING);
439             if (nameExpression == null)
440                 continue;
441
442             // NOTE: This assumes that nameEvaluator also makes sure that the
443             // evaluated names do not collide with any existing names in the
444             // model.
445             String evaluatedInstanceName = (String) nameEvaluator.apply(graph, typicalComposite, component, nameExpression);
446             if (evaluatedInstanceName != null && !evaluatedInstanceName.equals(nameExpression)) {
447                 if (DEBUG)
448                     System.out.println("TypicalUtil.applySelectionModuleNames: applied name expression " + nameExpression + " -> " + evaluatedInstanceName);
449                 graph.claimLiteral(component, L0.HasName, evaluatedInstanceName, Bindings.STRING);
450             }
451         }
452     }
453
454     /**
455      * @param graph
456      * @param typicalComposite
457      * @return f :: ReadGraph -> Resource composite -> Resource component -> String expression -> String name
458      * @throws DatabaseException
459      */
460     public static Function4<ReadGraph, Resource, Resource, String, String> getTypicalNamingFunction(ReadGraph graph, Resource typicalComposite) throws DatabaseException {
461         ModelingResources MOD = ModelingResources.getInstance(graph);
462         Function4<ReadGraph, Resource, Resource, String, String> nameEvaluator = graph.getPossibleRelatedValue2(typicalComposite, MOD.TypicalComposite_typicalNamingFunction);
463         return nameEvaluator;
464     }
465
466     /**
467      * @param processor
468      * @param model
469      * @return
470      * @throws DatabaseException
471      */
472     public static Collection<Resource> findModelTypicals(RequestProcessor processor, final Resource model) throws DatabaseException {
473         return processor.syncRequest(new UniqueRead<Collection<Resource>>() {
474             @Override
475             public Collection<Resource> perform(ReadGraph graph) throws DatabaseException {
476                 ModelingResources MOD = ModelingResources.getInstance(graph);
477                 Resource typicalMasterType = graph.getSingleObject(model, MOD.StructuralModel_HasMasterTypicalCompositeType);
478                 Instances query = graph.adapt(typicalMasterType, Instances.class);
479                 return query.find(graph, model);
480             }
481         });
482     }
483
484     /**
485      * A utility for synchronous execution of asynchronous procedures.
486      * @param runnable the callback that contains asynchronous execution
487      * @return the result received from the specified callback
488      * @throws DatabaseException
489      */
490     public static <T> T syncExec(Consumer<Procedure<T>> runnable) throws DatabaseException {
491         final AtomicReference<T> ref = new AtomicReference<T>();
492         final AtomicReference<Throwable> exc = new AtomicReference<Throwable>();
493         final Semaphore sem = new Semaphore(0);
494         runnable.accept(new Procedure<T>() {
495             @Override
496             public void execute(T result) {
497                 if (ref.compareAndSet(null, result))
498                     sem.release();
499             }
500             @Override
501             public void exception(Throwable t) {
502                 if (exc.compareAndSet(null, t))
503                     sem.release();
504             }
505         });
506         try {
507             sem.acquire();
508             Throwable t = exc.get();
509             if (t != null) {
510                 if (t instanceof DatabaseException)
511                     throw (DatabaseException) t;
512                 throw new DatabaseException(t);
513             } 
514             return (T) ref.get();
515         } catch (InterruptedException ex) {
516             throw new DatabaseException(ex);
517         }
518     }
519     
520     /*
521      * SCL API
522      */
523     public static void syncTypicalInstance(WriteGraph graph, Resource instance) throws DatabaseException {
524         SyncTypicalTemplatesToInstances sync = SyncTypicalTemplatesToInstances.syncSingleInstance(null, instance);
525         sync.perform(graph);
526     }
527     
528     /**
529      * Creates a new master typical diagram and its corresponding composites.
530      * 
531      * <p>
532      * The created typical composite and diagram type are specified by the model
533      * using {@link ModelingResources#StructuralModel_HasTypicalCompositeBaseType}
534      * and {@link ModelingResources#StructuralModel_HasTypicalDiagramBaseType}.
535      * 
536      * <p>
537      * Marks the created master composite with the model-specified master composite
538      * type to support searching. The master type is specified by the model using
539      * {@link ModelingResources#StructuralModel_HasMasterTypicalCompositeType}.
540      * 
541      * <p>
542      * Clones symbol contributions from the sources specified by the model through
543      * {@link ModelingResources#StructuralModel_CloneTypicalDiagramSymbolContributionsFrom}
544      * .
545      * 
546      * @author Tuukka Lehtonen
547      */
548
549     public static Resource newMasterTypical(final Resource target) throws DatabaseException {
550         
551         return Simantics.getSession().syncRequest(new WriteResultRequest<Resource>() {
552         
553             @Override
554             public Resource perform(WriteGraph graph) throws DatabaseException {
555                 Layer0 L0 = Layer0.getInstance(graph);
556                 Layer0X L0X = Layer0X.getInstance(graph);
557                 DiagramResource DIA = DiagramResource.getInstance(graph);
558                 ModelingResources MOD = ModelingResources.getInstance(graph);
559
560                 Resource indexRoot = graph.sync(new PossibleIndexRoot(target));
561                 if (indexRoot == null) {
562                     ShowMessage.showInformation("No Model or Shared Library", "Cannot find a containing model or shared library from the input selection. Typical master diagram creation not possible.");
563                     return null;
564                 }
565
566                 Resource compositeBaseType = graph.getPossibleObject(indexRoot, MOD.StructuralModel_HasTypicalCompositeBaseType);
567                 Resource diagramBaseType = graph.getPossibleObject(indexRoot, MOD.StructuralModel_HasTypicalDiagramBaseType);
568                 Resource masterCompositeType = graph.getPossibleObject(indexRoot, MOD.StructuralModel_HasMasterTypicalCompositeType);
569                 Collection<Resource> cloneSymbolContributionsFrom = graph.getObjects(indexRoot, MOD.StructuralModel_CloneTypicalDiagramSymbolContributionsFrom);
570                 if (compositeBaseType == null || diagramBaseType == null || masterCompositeType == null) {
571                     ShowMessage.showInformation("No Typical Support", "Creation of typical diagrams is not supported for this container.");
572                     return null;
573                 }
574
575                 Resource compositeType = graph.newResource();
576                 graph.claim(compositeType, L0.Inherits, compositeBaseType);
577                 String compositeTypeName = NameUtils.findFreshName(graph, "TypicalCompositeType", target);
578                 graph.claimLiteral(compositeType, L0.HasName, compositeTypeName);
579
580                 Resource diagramType = graph.newResource();
581                 graph.claim(diagramType, L0.Inherits, diagramBaseType);
582                 graph.claimLiteral(diagramType, L0.HasName, "Type");
583
584                 String name = NameUtils.findFreshName(graph, "Typical", target, L0.ConsistsOf, "%s%d");
585
586                 Resource composite = StructuralUtils.newComponent(graph, target, name + "@1", compositeType);
587                 graph.claim(composite, L0.InstanceOf, null, masterCompositeType);
588
589                 Resource diagram = graph.newResource();
590                 graph.claim(diagram, L0.InstanceOf, null, diagramType);
591                 graph.claimLiteral(diagram, L0.HasName, "__DIAGRAM__", Bindings.STRING);
592                 graph.claim(diagram, L0.SubrelationOf, null, L0.HasNext);
593                 graph.claim(diagram, MOD.DiagramToComposite, composite);
594                 Resource diagramInv = graph.newResource();
595                 graph.claim(diagramInv, L0.InverseOf, diagram);
596                 graph.claim(diagramInv, L0.SubrelationOf, null, L0.HasPrevious);
597                 graph.claimLiteral(diagramInv, L0.HasName, "Inverse", Bindings.STRING);
598                 graph.claim(diagram, L0.ConsistsOf, diagramInv);
599                 graph.claim(diagram, diagram, diagramInv, diagram);
600
601                 Resource mapping = graph.newResource();
602                 graph.claim(diagram, L0X.HasTrigger, mapping);
603                 graph.claim(mapping, L0.InstanceOf, null, MOD.DiagramToCompositeMapping);
604
605                 // Make diagram part of a dummy container entity attached to the parent
606                 // composite if it's not already part of something.
607                 Resource container = graph.newResource();
608                 graph.claim(container, L0.InstanceOf, null, DIA.DiagramContainer);
609                 graph.addLiteral(container, L0.HasName, L0.NameOf, L0.String, "__CONTAINER__", Bindings.STRING);
610
611                 // Compose all created resources into the following hierarchy:
612                 // Typical Composite : TypicalCompositeType
613                 //     Typical Composite Type : STR.CompositeType
614                 //     __CONTAINER__ : DIA.DiagramContainer
615                 //         "__DIAGRAM__" : "Type"
616                 //             "Type" <T DIA.Diagram
617                 graph.claim(diagram, L0.ConsistsOf, diagramType);
618                 graph.claim(container, L0.ConsistsOf, diagram);
619                 graph.claim(composite, L0.ConsistsOf, container);
620                 graph.claim(composite, L0.ConsistsOf, compositeType);
621
622                 // Attach the same symbol contributions to the created typical
623                 // diagram type as are attached to the model-designated
624                 // contribution source diagram type.
625                 boolean clonedIndexRootContribution = false;
626                 for (Resource symbolContributionSource : cloneSymbolContributionsFrom) {
627                     for (Resource contribution : graph.getObjects(symbolContributionSource, DIA.HasSymbolContribution)) {
628                         graph.claim(diagramType, DIA.HasSymbolContribution, contribution);
629                         clonedIndexRootContribution |= graph.isInstanceOf(contribution, DIA.IndexRootSymbolContribution);
630                     }
631                 }
632
633                 if (!clonedIndexRootContribution) {
634                     Resource indexContribution = graph.newResource();
635                     graph.claim(indexContribution, L0.InstanceOf, DIA.IndexRootSymbolContribution);
636                     graph.claim(diagramType, DIA.HasSymbolContribution, indexContribution);
637                 }
638
639                 // Add comment to change set.
640                 CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
641                 graph.addMetadata(cm.add("Created typical master diagram " + composite));
642
643                 return composite;
644             }
645         });
646     
647     }
648 }
649