]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/TypicalUtil.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / typicals / TypicalUtil.java
diff --git a/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/TypicalUtil.java b/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/TypicalUtil.java
new file mode 100644 (file)
index 0000000..9c29290
--- /dev/null
@@ -0,0 +1,642 @@
+/*******************************************************************************\r
+ * Copyright (c) 2012 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.modeling.typicals;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.concurrent.Semaphore;\r
+import java.util.concurrent.atomic.AtomicReference;\r
+import java.util.function.Consumer;\r
+\r
+import org.simantics.NameLabelMode;\r
+import org.simantics.NameLabelUtil;\r
+import org.simantics.Simantics;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.RequestProcessor;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.WriteOnlyGraph;\r
+import org.simantics.db.common.CommentMetadata;\r
+import org.simantics.db.common.NamedResource;\r
+import org.simantics.db.common.request.FreshName;\r
+import org.simantics.db.common.request.ObjectsWithType;\r
+import org.simantics.db.common.request.PossibleIndexRoot;\r
+import org.simantics.db.common.request.UniqueRead;\r
+import org.simantics.db.common.request.WriteResultRequest;\r
+import org.simantics.db.common.uri.UnescapedChildMapOfResource;\r
+import org.simantics.db.common.utils.CommonDBUtils;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.RuntimeDatabaseException;\r
+import org.simantics.db.layer0.adapter.CopyHandler;\r
+import org.simantics.db.layer0.adapter.Instances;\r
+import org.simantics.db.layer0.request.Configuration;\r
+import org.simantics.db.layer0.request.PossibleModel;\r
+import org.simantics.db.layer0.util.ClipboardUtils;\r
+import org.simantics.db.layer0.util.SimanticsClipboard.Representation;\r
+import org.simantics.db.layer0.util.SimanticsClipboardImpl;\r
+import org.simantics.db.layer0.util.SimanticsKeys;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.layer0.variable.Variables;\r
+import org.simantics.db.procedure.Procedure;\r
+import org.simantics.db.request.WriteResult;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.graph.db.IImportAdvisor;\r
+import org.simantics.graph.db.TransferableGraphs;\r
+import org.simantics.graph.representation.Root;\r
+import org.simantics.graph.representation.TransferableGraph1;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.modeling.ModelingUtils.CompositeInfo;\r
+import org.simantics.modeling.ModelingUtils.DiagramComponentInfo;\r
+import org.simantics.modeling.services.ComponentNamingUtil;\r
+import org.simantics.modeling.services.NamingException;\r
+import org.simantics.operation.Layer0X;\r
+import org.simantics.scl.runtime.function.Function2;\r
+import org.simantics.scl.runtime.function.Function4;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.structural2.utils.StructuralUtils;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.utils.datastructures.Pair;\r
+import org.simantics.utils.ui.dialogs.ShowMessage;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class TypicalUtil {\r
+\r
+    private static final boolean DEBUG = false;\r
+\r
+    private static class TypicalNamingFunction implements Function2<ReadGraph, Resource, String> {\r
+        private NameLabelMode mode;\r
+\r
+        @Override\r
+        public String apply(ReadGraph graph, Resource r) {\r
+            try {\r
+                if (mode == null)\r
+                    mode = NameLabelUtil.getNameLabelMode(graph);\r
+                Variable v = Variables.getPossibleVariable(graph, r);\r
+                if (v != null) {\r
+                    Resource root = Variables.getPossibleIndexRoot(graph, v);\r
+                    if (root != null) {\r
+                        Variable rootV = Variables.getVariable(graph, root);\r
+                        List<Variable> path = Variables.getPath(graph, rootV, v);\r
+                        path.add(0, rootV);\r
+                        return typicalLabel(graph, v, path);\r
+                    }\r
+                }\r
+                return TypicalUtil.getName(graph, r);\r
+            } catch (DatabaseException e) {\r
+                throw new RuntimeDatabaseException(e);\r
+            }\r
+        }\r
+\r
+        protected String typicalLabel(ReadGraph graph, Variable v, List<Variable> path) throws DatabaseException {\r
+            StringBuilder sb = new StringBuilder();\r
+            labelVariable(graph, v, sb);\r
+            if (path.size() > 0) {\r
+                sb.append(" (");\r
+                for (Variable vv : path) {\r
+                    sb.append("/");\r
+                    labelVariable(graph, vv, sb);\r
+                }\r
+                sb.append(")");\r
+            }\r
+            return sb.toString();\r
+        }\r
+\r
+        protected StringBuilder labelVariable(ReadGraph graph, Variable v, StringBuilder result) throws DatabaseException {\r
+            Resource r = v.getPossibleRepresents(graph);\r
+            if (r != null) {\r
+                result.append(NameLabelUtil.modalName(graph, r, mode));\r
+            } else {\r
+                result.append(NameLabelUtil.modalName(graph, v, mode));\r
+            }\r
+            return result;\r
+        }\r
+    };\r
+\r
+    public static Collection<NamedResource> toNamedResources(RequestProcessor processor, final Collection<Resource> rs) throws DatabaseException {\r
+        return toNamedResources(processor, rs, new TypicalNamingFunction());\r
+    }\r
+\r
+    public static Collection<NamedResource> toNamedResources(RequestProcessor processor, final Collection<Resource> rs, final Function2<ReadGraph, Resource, String> namingFunction) throws DatabaseException {\r
+        return processor.syncRequest(new UniqueRead<Collection<NamedResource>>() {\r
+            @Override\r
+            public Collection<NamedResource> perform(ReadGraph graph) throws DatabaseException {\r
+                return toNamedResources(graph, rs, namingFunction);\r
+            }\r
+        });\r
+    }\r
+\r
+    public static Collection<NamedResource> toNamedResources(ReadGraph graph, Collection<Resource> rs, final Function2<ReadGraph, Resource, String> namingFunction) throws DatabaseException {\r
+        Collection<NamedResource> result = new ArrayList<NamedResource>(rs.size());\r
+        for (Resource r : rs)\r
+            result.add(new NamedResource(namingFunction.apply(graph, r), r));\r
+        return result;\r
+    }\r
+\r
+    public static String getName(ReadGraph graph, Resource r) throws DatabaseException {\r
+        String s = graph.getPossibleAdapter(r, String.class);\r
+        if (s == null)\r
+            s = NameUtils.getSafeLabel(graph, r);\r
+        return s;\r
+    }\r
+\r
+    public static WriteResult<Resource> instantiateTemplate(final Resource target, final NamedResource template,\r
+            final Consumer<Pair<WriteGraph, Resource>> successContinuation) {\r
+        return new WriteResultRequest<Resource>() {\r
+            @Override\r
+            public Resource perform(WriteGraph graph) throws DatabaseException {\r
+                // Custom instantiation by copying the original and mapping the original to the copy\r
+               CommonDBUtils.selectClusterSet(graph, target);\r
+                SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();\r
+                CopyHandler ch = new TypicalCompositeCopyHandler(template.getResource());\r
+                ch.copyToClipboard(graph, clipboard);\r
+\r
+                Map<String,Object> hints = Collections.singletonMap(ClipboardUtils.HINT_TARGET_RESOURCE, target);\r
+\r
+                for (Set<Representation> object : clipboard.getContents()) {\r
+                    TransferableGraph1 tg = ClipboardUtils.accept(graph, object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH, hints);\r
+                    if (tg != null) {\r
+                        DiagramPasteImportAdvisor advisor = new DiagramPasteImportAdvisor(graph, target, template.getName());\r
+                        TransferableGraphs.importGraph1(graph, tg, advisor);\r
+                        Resource copy = advisor.getRoot();\r
+\r
+                        configureCopyType(graph, copy, template.getResource());\r
+                        associateCopyToTemplate(graph, copy, template.getResource());\r
+\r
+                        if (successContinuation!= null)\r
+                            successContinuation.accept(Pair.make(graph, copy));\r
+\r
+                        return copy;\r
+                    }\r
+                }\r
+                throw new DatabaseException("Failed to instantiate typical template through clipboard");\r
+            }\r
+        };\r
+    }\r
+\r
+    public static void configureCopyType(WriteGraph graph, Resource copy, Resource template) throws DatabaseException {\r
+        // Remove master template instance tag type(s)\r
+        Layer0 L0 = Layer0.getInstance(graph);\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        ModelingResources MOD = ModelingResources.getInstance(graph);\r
+        for (Resource type : graph.getObjects(template, L0.InstanceOf)) {\r
+            if (graph.isInheritedFrom(type, MOD.MasterTypicalCompositeType))\r
+                graph.deny(copy, L0.InstanceOf, type);\r
+            else\r
+                graph.claim(copy, L0.InstanceOf, null, type);\r
+        }\r
+        for (Resource templateDiagram : graph.getObjects(template, MOD.CompositeToDiagram)) {\r
+            Resource templateDiagramType = graph.getPossibleType(templateDiagram, DIA.Diagram);\r
+            if (templateDiagramType != null) {\r
+                for (Resource copiedDiagram : graph.getObjects(copy, MOD.CompositeToDiagram)) {\r
+                    graph.claim(copiedDiagram, L0.InstanceOf, null, templateDiagramType);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    public static void associateCopyToTemplate(WriteGraph graph, Resource copy, Resource template) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        ModelingResources MOD = ModelingResources.getInstance(graph);\r
+        Resource templateDiagram = graph.getSingleObject(template, MOD.CompositeToDiagram);\r
+        Resource copyDiagram = graph.getSingleObject(copy, MOD.CompositeToDiagram);\r
+        Map<String, Resource> templateDiagramElements = graph.syncRequest(new UnescapedChildMapOfResource(templateDiagram));\r
+        Map<String, Resource> copyDiagramElements = graph.syncRequest(new UnescapedChildMapOfResource(copyDiagram));\r
+\r
+        // Associations are intentionally bi-directional\r
+        graph.claim(copyDiagram, MOD.HasDiagramSource, MOD.DiagramHasInstance, templateDiagram);\r
+        for (String element : templateDiagramElements.keySet()) {\r
+            Resource templateElement = templateDiagramElements.get(element);\r
+            if (!graph.isInstanceOf(templateElement, DIA.Element))\r
+                continue;\r
+            Resource copyElement = copyDiagramElements.get(element);\r
+            graph.claim(copyElement, MOD.HasElementSource, MOD.ElementHasInstance, templateElement);\r
+            graph.claim(copyElement, MOD.IsTemplatized, MOD.IsTemplatized, copyElement);\r
+        }\r
+\r
+        Long modCount = graph.getPossibleRelatedValue(copyDiagram, DIA.HasModCount);\r
+        if (modCount == null)\r
+            modCount = 0L;\r
+        modCount += 1L << 32;\r
+        graph.claimLiteral(copyDiagram, DiagramResource.getInstance(graph).HasModCount, modCount, Bindings.LONG);\r
+    }\r
+\r
+    /**\r
+     * @param graph\r
+     * @param typicalCompositeInstance\r
+     * @param excludedComponents the set of components in the specified\r
+     *        composite that are not freshly renamed or <code>null</code> to\r
+     *        freshly name all components\r
+     * @throws DatabaseException\r
+     */\r
+    public static void generateFreshModuleNames(WriteGraph graph, Resource typicalCompositeInstance, Set<Resource> excludedComponents) throws DatabaseException {\r
+        Layer0 L0 = Layer0.getInstance(graph);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+        Resource configurationRoot = graph.sync(new Configuration(typicalCompositeInstance));\r
+        for(Map.Entry<String, Resource> entry : graph.syncRequest(new UnescapedChildMapOfResource(typicalCompositeInstance)).entrySet()) {\r
+            Resource component = entry.getValue();\r
+            if (!graph.isInstanceOf(component, STR.Component))\r
+                continue;\r
+            if (excludedComponents != null && excludedComponents.contains(component))\r
+                continue;\r
+            try {\r
+                String renamed = ComponentNamingUtil.findFreshInstanceName(graph, SimanticsUI.getProject(), configurationRoot, typicalCompositeInstance, component);\r
+                if (DEBUG)\r
+                    System.out.println("Typicals: renamed " + entry.getKey() + " -> " + renamed);\r
+                graph.claimLiteral(entry.getValue(), L0.HasName, L0.NameOf, renamed, Bindings.STRING);\r
+            } catch (NamingException e) {\r
+                throw new DatabaseException(e);\r
+            }\r
+        }\r
+    }\r
+\r
+    public static class DiagramPasteImportAdvisor implements IImportAdvisor {\r
+\r
+        protected final Resource library;\r
+        protected final Resource model;\r
+        protected Resource diagram;\r
+        protected final String diagramName;\r
+\r
+        public DiagramPasteImportAdvisor(ReadGraph graph, Resource library, String originalName) throws DatabaseException {\r
+            this.library = library;\r
+            this.diagram = null;\r
+            this.diagramName = graph.syncRequest(new FreshName(library, originalName));\r
+            this.model = graph.syncRequest(new PossibleModel(library));\r
+        }\r
+\r
+        public void analyzeType(ReadGraph graph, Root root) throws DatabaseException {\r
+        }\r
+\r
+       @Override\r
+       public Resource analyzeRoot(ReadGraph graph, Root root) throws DatabaseException {\r
+               if("%model".equals(root.name)) return model;\r
+               return null;\r
+       }\r
+        @Override\r
+        public Resource createRoot(WriteOnlyGraph graph, Root root) throws DatabaseException {\r
+\r
+               Layer0 l0 = graph.getService(Layer0.class);\r
+            if(CompositeInfo.isComposite(root.name)) {\r
+                // Use existing if available\r
+                if(diagram == null) diagram = graph.newResource();\r
+                graph.claim(library, l0.ConsistsOf, l0.PartOf, diagram);\r
+                graph.newClusterSet(diagram);\r
+                graph.setClusterSet4NewResource(diagram);\r
+                graph.addLiteral(diagram, l0.HasName, l0.NameOf, l0.String, diagramName, Bindings.STRING);\r
+                return diagram;\r
+            } else if (DiagramComponentInfo.isDiagramComponent(root.name)) {\r
+               DiagramComponentInfo info = DiagramComponentInfo.parse(root.name);\r
+                Resource child = graph.newResource();\r
+                graph.addLiteral(child, l0.HasName, l0.NameOf, l0.String, info.getUnescapedComponentName(), Bindings.STRING);\r
+                return child;\r
+            } else {\r
+                throw new DatabaseException("Unclassified root " + root.name);\r
+            }\r
+\r
+        }\r
+\r
+        public Resource getRoot() {\r
+            return diagram;\r
+        }\r
+\r
+    }\r
+\r
+    /**\r
+     * @param graph\r
+     * @param typicalInstanceComposite\r
+     * @param renamedComponentsOutput a set that can be provided to get the set\r
+     *        of components that was renamed as output from this method or\r
+     *        <code>null</code> to not collect renamed components\r
+     * @throws DatabaseException\r
+     */\r
+    public static void applyTypicalModuleNames(WriteGraph graph, Resource typicalInstanceComposite, Set<Resource> renamedComponentsOutput) throws DatabaseException {\r
+       \r
+        Layer0 L0 = Layer0.getInstance(graph);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(graph); \r
+\r
+        Function4<ReadGraph, Resource, Resource, String, String> nameEvaluator = getTypicalNamingFunction(graph, typicalInstanceComposite);\r
+        if (nameEvaluator == null)\r
+            return;\r
+\r
+        Collection<Resource> components = graph.syncRequest(new ObjectsWithType(typicalInstanceComposite, L0.ConsistsOf, STR.Component));\r
+        for (Resource component : components) {\r
+               applyTypicalModuleName(graph, component, nameEvaluator, renamedComponentsOutput);  \r
+        }\r
+        \r
+    }\r
+\r
+    public static boolean applyTypicalModuleName(WriteGraph graph, Resource instanceComponent, Function4<ReadGraph, Resource, Resource, String, String> nameEvaluator, Set<Resource> renamedComponentsOutput) throws DatabaseException {\r
+\r
+        Layer0 L0 = Layer0.getInstance(graph);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(graph); \r
+        ModelingResources MOD = ModelingResources.getInstance(graph);\r
+\r
+        Resource componentType = graph.getPossibleType(instanceComponent, STR.Component);\r
+        if (componentType == null)\r
+            return false;\r
+\r
+        Resource instanceElement = graph.getPossibleObject(instanceComponent, MOD.ComponentToElement);\r
+        if (instanceElement == null)\r
+            return false;\r
+\r
+        Resource templateElement = graph.getPossibleObject(instanceElement, MOD.HasElementSource);\r
+        if (templateElement == null)\r
+            return false;\r
+\r
+        Resource templateComponent = graph.getPossibleObject(templateElement, MOD.ElementToComponent);\r
+        if (templateComponent == null)\r
+            return false;\r
+\r
+        // TODO: Use variables and EXPRESSION property instead ?\r
+        String nameExpression = graph.getPossibleRelatedValue(templateComponent, L0.HasName, Bindings.STRING);\r
+        if (nameExpression == null)\r
+            return false;\r
+\r
+        Resource instanceComposite = graph.getPossibleObject(instanceComponent, L0.PartOf);\r
+        if (instanceComposite == null)\r
+            return false;\r
+        \r
+        // This evaluator replaces % with assigned primary position name\r
+        String evaluatedInstanceName = (String) nameEvaluator.apply(graph, instanceComposite, instanceComponent, nameExpression);\r
+        if(evaluatedInstanceName == null)\r
+               return false;\r
+\r
+       String instanceName = graph.getPossibleRelatedValue(instanceComponent, L0.HasName, Bindings.STRING);\r
+       if(instanceName == null)\r
+               return false;\r
+\r
+       if(!evaluatedInstanceName.equals(instanceName)) {\r
+               \r
+            graph.claimLiteral(instanceComponent, L0.HasName, evaluatedInstanceName, Bindings.STRING);\r
+            if (renamedComponentsOutput != null)\r
+                renamedComponentsOutput.add(instanceComponent);\r
+            \r
+            if (DEBUG)\r
+               System.out.println("TypicalUtil.applyTypicalModuleName: applied name expression " + nameExpression + " -> " + instanceName + " -> " + evaluatedInstanceName);\r
+            \r
+            return true;\r
+               \r
+       }\r
+        \r
+        return false;\r
+       \r
+    }\r
+    \r
+    /**\r
+     * @param graph\r
+     * @param typicalComposite\r
+     * @param componentsToCheck the set of components to check for required\r
+     *        naming\r
+     * @throws DatabaseException\r
+     */\r
+    public static void applySelectedModuleNames(WriteGraph graph, Resource typicalComposite, List<Resource> componentsToCheck) throws DatabaseException {\r
+        Layer0 L0 = Layer0.getInstance(graph);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(graph); \r
+        ModelingResources MOD = ModelingResources.getInstance(graph);\r
+\r
+        Function4<ReadGraph, Resource, Resource, String, String> nameEvaluator = getTypicalNamingFunction(graph, typicalComposite);\r
+        if (nameEvaluator == null)\r
+            return;\r
+\r
+        for (Resource component : componentsToCheck) {\r
+            Resource componentType = graph.getPossibleType(component, STR.Component);\r
+            if (componentType == null)\r
+                continue;\r
+\r
+            Resource element = graph.getPossibleObject(component, MOD.ComponentToElement);\r
+            if (element == null)\r
+                continue;\r
+\r
+            Resource templateElement = graph.getPossibleObject(element, MOD.HasElementSource);\r
+            if (templateElement == null)\r
+                continue;\r
+\r
+            Resource templateComponent = graph.getPossibleObject(templateElement, MOD.ElementToComponent);\r
+            if (templateComponent == null)\r
+                continue;\r
+\r
+            String nameExpression = graph.getPossibleRelatedValue(templateComponent, L0.HasName, Bindings.STRING);\r
+            if (nameExpression == null)\r
+                continue;\r
+\r
+            // NOTE: This assumes that nameEvaluator also makes sure that the\r
+            // evaluated names do not collide with any existing names in the\r
+            // model.\r
+            String evaluatedInstanceName = (String) nameEvaluator.apply(graph, typicalComposite, component, nameExpression);\r
+            if (evaluatedInstanceName != null && !evaluatedInstanceName.equals(nameExpression)) {\r
+                if (DEBUG)\r
+                    System.out.println("TypicalUtil.applySelectionModuleNames: applied name expression " + nameExpression + " -> " + evaluatedInstanceName);\r
+                graph.claimLiteral(component, L0.HasName, evaluatedInstanceName, Bindings.STRING);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * @param graph\r
+     * @param typicalComposite\r
+     * @return f :: ReadGraph -> Resource composite -> Resource component -> String expression -> String name\r
+     * @throws DatabaseException\r
+     */\r
+    public static Function4<ReadGraph, Resource, Resource, String, String> getTypicalNamingFunction(ReadGraph graph, Resource typicalComposite) throws DatabaseException {\r
+        ModelingResources MOD = ModelingResources.getInstance(graph);\r
+        Function4<ReadGraph, Resource, Resource, String, String> nameEvaluator = graph.getPossibleRelatedValue2(typicalComposite, MOD.TypicalComposite_typicalNamingFunction);\r
+        return nameEvaluator;\r
+    }\r
+\r
+    /**\r
+     * @param processor\r
+     * @param model\r
+     * @return\r
+     * @throws DatabaseException\r
+     */\r
+    public static Collection<Resource> findModelTypicals(RequestProcessor processor, final Resource model) throws DatabaseException {\r
+        return processor.syncRequest(new UniqueRead<Collection<Resource>>() {\r
+            @Override\r
+            public Collection<Resource> perform(ReadGraph graph) throws DatabaseException {\r
+                ModelingResources MOD = ModelingResources.getInstance(graph);\r
+                Resource typicalMasterType = graph.getSingleObject(model, MOD.StructuralModel_HasMasterTypicalCompositeType);\r
+                Instances query = graph.adapt(typicalMasterType, Instances.class);\r
+                return query.find(graph, model);\r
+            }\r
+        });\r
+    }\r
+\r
+    /**\r
+     * A utility for synchronous execution of asynchronous procedures.\r
+     * @param runnable the callback that contains asynchronous execution\r
+     * @return the result received from the specified callback\r
+     * @throws DatabaseException\r
+     */\r
+    public static <T> T syncExec(Consumer<Procedure<T>> runnable) throws DatabaseException {\r
+        final AtomicReference<T> ref = new AtomicReference<T>();\r
+        final AtomicReference<Throwable> exc = new AtomicReference<Throwable>();\r
+        final Semaphore sem = new Semaphore(0);\r
+        runnable.accept(new Procedure<T>() {\r
+            @Override\r
+            public void execute(T result) {\r
+                if (ref.compareAndSet(null, result))\r
+                    sem.release();\r
+            }\r
+            @Override\r
+            public void exception(Throwable t) {\r
+                if (exc.compareAndSet(null, t))\r
+                    sem.release();\r
+            }\r
+        });\r
+        try {\r
+            sem.acquire();\r
+            Throwable t = exc.get();\r
+            if (t != null) {\r
+                if (t instanceof DatabaseException)\r
+                    throw (DatabaseException) t;\r
+                throw new DatabaseException(t);\r
+            } \r
+            return (T) ref.get();\r
+        } catch (InterruptedException ex) {\r
+            throw new DatabaseException(ex);\r
+        }\r
+    }\r
+    \r
+    /*\r
+     * SCL API\r
+     */\r
+    public static void syncTypicalInstance(WriteGraph graph, Resource instance) throws DatabaseException {\r
+       SyncTypicalTemplatesToInstances sync = SyncTypicalTemplatesToInstances.syncSingleInstance(null, instance);\r
+       sync.perform(graph);\r
+    }\r
+    \r
+    /**\r
+     * Creates a new master typical diagram and its corresponding composites.\r
+     * \r
+     * <p>\r
+     * The created typical composite and diagram type are specified by the model\r
+     * using {@link ModelingResources#StructuralModel_HasTypicalCompositeBaseType}\r
+     * and {@link ModelingResources#StructuralModel_HasTypicalDiagramBaseType}.\r
+     * \r
+     * <p>\r
+     * Marks the created master composite with the model-specified master composite\r
+     * type to support searching. The master type is specified by the model using\r
+     * {@link ModelingResources#StructuralModel_HasMasterTypicalCompositeType}.\r
+     * \r
+     * <p>\r
+     * Clones symbol contributions from the sources specified by the model through\r
+     * {@link ModelingResources#StructuralModel_CloneTypicalDiagramSymbolContributionsFrom}\r
+     * .\r
+     * \r
+     * @author Tuukka Lehtonen\r
+     */\r
+\r
+    public static Resource newMasterTypical(final Resource target) throws DatabaseException {\r
+       \r
+       return Simantics.getSession().syncRequest(new WriteResultRequest<Resource>() {\r
+       \r
+            @Override\r
+            public Resource perform(WriteGraph graph) throws DatabaseException {\r
+                Layer0 L0 = Layer0.getInstance(graph);\r
+                Layer0X L0X = Layer0X.getInstance(graph);\r
+                DiagramResource DIA = DiagramResource.getInstance(graph);\r
+                ModelingResources MOD = ModelingResources.getInstance(graph);\r
+\r
+                Resource indexRoot = graph.sync(new PossibleIndexRoot(target));\r
+                if (indexRoot == null) {\r
+                    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
+                    return null;\r
+                }\r
+\r
+                Resource compositeBaseType = graph.getPossibleObject(indexRoot, MOD.StructuralModel_HasTypicalCompositeBaseType);\r
+                Resource diagramBaseType = graph.getPossibleObject(indexRoot, MOD.StructuralModel_HasTypicalDiagramBaseType);\r
+                Resource masterCompositeType = graph.getPossibleObject(indexRoot, MOD.StructuralModel_HasMasterTypicalCompositeType);\r
+                Collection<Resource> cloneSymbolContributionsFrom = graph.getObjects(indexRoot, MOD.StructuralModel_CloneTypicalDiagramSymbolContributionsFrom);\r
+                if (compositeBaseType == null || diagramBaseType == null || masterCompositeType == null) {\r
+                    ShowMessage.showInformation("No Typical Support", "Creation of typical diagrams is not supported for this container.");\r
+                    return null;\r
+                }\r
+\r
+                Resource compositeType = graph.newResource();\r
+                graph.claim(compositeType, L0.Inherits, compositeBaseType);\r
+                String compositeTypeName = NameUtils.findFreshName(graph, "TypicalCompositeType", target);\r
+                graph.claimLiteral(compositeType, L0.HasName, compositeTypeName);\r
+\r
+                Resource diagramType = graph.newResource();\r
+                graph.claim(diagramType, L0.Inherits, diagramBaseType);\r
+                graph.claimLiteral(diagramType, L0.HasName, "Type");\r
+\r
+                String name = NameUtils.findFreshName(graph, "Typical", target, L0.ConsistsOf, "%s%d");\r
+\r
+                Resource composite = StructuralUtils.newComponent(graph, target, name + "@1", compositeType);\r
+                graph.claim(composite, L0.InstanceOf, null, masterCompositeType);\r
+\r
+                Resource diagram = graph.newResource();\r
+                graph.claim(diagram, L0.InstanceOf, null, diagramType);\r
+                graph.claimLiteral(diagram, L0.HasName, "__DIAGRAM__", Bindings.STRING);\r
+                graph.claim(diagram, L0.SubrelationOf, null, L0.HasNext);\r
+                graph.claim(diagram, MOD.DiagramToComposite, composite);\r
+                Resource diagramInv = graph.newResource();\r
+                graph.claim(diagramInv, L0.InverseOf, diagram);\r
+                graph.claim(diagramInv, L0.SubrelationOf, null, L0.HasPrevious);\r
+                graph.claimLiteral(diagramInv, L0.HasName, "Inverse", Bindings.STRING);\r
+                graph.claim(diagram, L0.ConsistsOf, diagramInv);\r
+                graph.claim(diagram, diagram, diagramInv, diagram);\r
+\r
+                Resource mapping = graph.newResource();\r
+                graph.claim(diagram, L0X.HasTrigger, mapping);\r
+                graph.claim(mapping, L0.InstanceOf, null, MOD.DiagramToCompositeMapping);\r
+\r
+                // Make diagram part of a dummy container entity attached to the parent\r
+                // composite if it's not already part of something.\r
+                Resource container = graph.newResource();\r
+                graph.claim(container, L0.InstanceOf, null, DIA.DiagramContainer);\r
+                graph.addLiteral(container, L0.HasName, L0.NameOf, L0.String, "__CONTAINER__", Bindings.STRING);\r
+\r
+                // Compose all created resources into the following hierarchy:\r
+                // Typical Composite : TypicalCompositeType\r
+                //     Typical Composite Type : STR.CompositeType\r
+                //     __CONTAINER__ : DIA.DiagramContainer\r
+                //         "__DIAGRAM__" : "Type"\r
+                //             "Type" <T DIA.Diagram\r
+                graph.claim(diagram, L0.ConsistsOf, diagramType);\r
+                graph.claim(container, L0.ConsistsOf, diagram);\r
+                graph.claim(composite, L0.ConsistsOf, container);\r
+                graph.claim(composite, L0.ConsistsOf, compositeType);\r
+\r
+                // Attach the same symbol contributions to the created typical\r
+                // diagram type as are attached to the model-designated\r
+                // contribution source diagram type.\r
+                for (Resource symbolContributionSource : cloneSymbolContributionsFrom) {\r
+                    for (Resource contribution : graph.getObjects(symbolContributionSource, DIA.HasSymbolContribution)) {\r
+                        graph.claim(diagramType, DIA.HasSymbolContribution, contribution);\r
+                    }\r
+                }\r
+\r
+                Resource indexContribution = graph.newResource();\r
+                graph.claim(indexContribution, L0.InstanceOf, DIA.IndexRootSymbolContribution);\r
+                graph.claim(diagramType, DIA.HasSymbolContribution, indexContribution);\r
+\r
+                // Add comment to change set.\r
+                CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
+                graph.addMetadata(cm.add("Created typical master diagram " + composite));\r
+\r
+                return composite;\r
+            }\r
+        });\r
+    \r
+    }\r
+}\r
+\r