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