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