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