X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.modeling%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Ftypicals%2FTypicalUtil.java;h=a92d7b62643d713ac3095f1d7df58966e8cb80f2;hp=e15f5036d9be684d25fe5f2e7d8b315b229f8b36;hb=e88be95edf1f80781646cfdf717ec1b663264179;hpb=23755ed9225d2e231bcde85c5f6a36d1e1040c16 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 index e15f5036d..a92d7b626 100644 --- a/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/TypicalUtil.java +++ b/bundles/org.simantics.modeling/src/org/simantics/modeling/typicals/TypicalUtil.java @@ -1,646 +1,649 @@ -/******************************************************************************* - * 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.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.ui.SimanticsUI; -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 { - 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 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 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 Collection toNamedResources(RequestProcessor processor, final Collection rs) throws DatabaseException { - return toNamedResources(processor, rs, new TypicalNamingFunction()); - } - - public static Collection toNamedResources(RequestProcessor processor, final Collection rs, final Function2 namingFunction) throws DatabaseException { - return processor.syncRequest(new UniqueRead>() { - @Override - public Collection perform(ReadGraph graph) throws DatabaseException { - return toNamedResources(graph, rs, namingFunction); - } - }); - } - - public static Collection toNamedResources(ReadGraph graph, Collection rs, final Function2 namingFunction) throws DatabaseException { - Collection 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 instantiateTemplate(final Resource target, final NamedResource template, - final Consumer> successContinuation) { - return new WriteResultRequest() { - @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); - - Map hints = Collections.singletonMap(ClipboardUtils.HINT_TARGET_RESOURCE, target); - - for (Set 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 templateDiagramElements = graph.syncRequest(new UnescapedChildMapOfResource(templateDiagram)); - Map 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 null to - * freshly name all components - * @throws DatabaseException - */ - public static void generateFreshModuleNames(WriteGraph graph, Resource typicalCompositeInstance, Set excludedComponents) throws DatabaseException { - Layer0 L0 = Layer0.getInstance(graph); - StructuralResource2 STR = StructuralResource2.getInstance(graph); - Resource configurationRoot = graph.sync(new Configuration(typicalCompositeInstance)); - for(Map.Entry 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, SimanticsUI.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 - * null to not collect renamed components - * @throws DatabaseException - */ - public static void applyTypicalModuleNames(WriteGraph graph, Resource typicalInstanceComposite, Set renamedComponentsOutput) throws DatabaseException { - - Layer0 L0 = Layer0.getInstance(graph); - StructuralResource2 STR = StructuralResource2.getInstance(graph); - - Function4 nameEvaluator = getTypicalNamingFunction(graph, typicalInstanceComposite); - if (nameEvaluator == null) - return; - - Collection 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 nameEvaluator, Set 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 componentsToCheck) throws DatabaseException { - Layer0 L0 = Layer0.getInstance(graph); - StructuralResource2 STR = StructuralResource2.getInstance(graph); - ModelingResources MOD = ModelingResources.getInstance(graph); - - Function4 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 getTypicalNamingFunction(ReadGraph graph, Resource typicalComposite) throws DatabaseException { - ModelingResources MOD = ModelingResources.getInstance(graph); - Function4 nameEvaluator = graph.getPossibleRelatedValue2(typicalComposite, MOD.TypicalComposite_typicalNamingFunction); - return nameEvaluator; - } - - /** - * @param processor - * @param model - * @return - * @throws DatabaseException - */ - public static Collection findModelTypicals(RequestProcessor processor, final Resource model) throws DatabaseException { - return processor.syncRequest(new UniqueRead>() { - @Override - public Collection 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 syncExec(Consumer> runnable) throws DatabaseException { - final AtomicReference ref = new AtomicReference(); - final AtomicReference exc = new AtomicReference(); - final Semaphore sem = new Semaphore(0); - runnable.accept(new Procedure() { - @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. - * - *

- * The created typical composite and diagram type are specified by the model - * using {@link ModelingResources#StructuralModel_HasTypicalCompositeBaseType} - * and {@link ModelingResources#StructuralModel_HasTypicalDiagramBaseType}. - * - *

- * 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}. - * - *

- * 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() { - - @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 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" { + 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 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 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 toNamedResources(RequestProcessor processor, final Collection rs) throws DatabaseException { + return toNamedResources(processor, rs, new TypicalNamingFunction()); + } + + public static List toNamedResources(RequestProcessor processor, final Collection rs, final Function2 namingFunction) throws DatabaseException { + return processor.syncRequest(new UniqueRead>() { + @Override + public List perform(ReadGraph graph) throws DatabaseException { + return toNamedResources(graph, rs, namingFunction); + } + }); + } + + public static List toNamedResources(ReadGraph graph, Collection rs, final Function2 namingFunction) throws DatabaseException { + List 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 instantiateTemplate( + Resource target, + NamedResource template, + Consumer> successContinuation) + { + return new WriteResultRequest() { + @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); + + Map hints = Collections.singletonMap(ClipboardUtils.HINT_TARGET_RESOURCE, target); + + for (Set 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 templateDiagramElements = graph.syncRequest(new UnescapedChildMapOfResource(templateDiagram)); + Map 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 null to + * freshly name all components + * @throws DatabaseException + */ + public static void generateFreshModuleNames(WriteGraph graph, Resource typicalCompositeInstance, Set excludedComponents) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + StructuralResource2 STR = StructuralResource2.getInstance(graph); + Resource configurationRoot = graph.sync(new Configuration(typicalCompositeInstance)); + for(Map.Entry 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 + * null to not collect renamed components + * @throws DatabaseException + */ + public static void applyTypicalModuleNames(WriteGraph graph, Resource typicalInstanceComposite, Set renamedComponentsOutput) throws DatabaseException { + + Layer0 L0 = Layer0.getInstance(graph); + StructuralResource2 STR = StructuralResource2.getInstance(graph); + + Function4 nameEvaluator = getTypicalNamingFunction(graph, typicalInstanceComposite); + if (nameEvaluator == null) + return; + + Collection 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 nameEvaluator, Set 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 componentsToCheck) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + StructuralResource2 STR = StructuralResource2.getInstance(graph); + ModelingResources MOD = ModelingResources.getInstance(graph); + + Function4 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 getTypicalNamingFunction(ReadGraph graph, Resource typicalComposite) throws DatabaseException { + ModelingResources MOD = ModelingResources.getInstance(graph); + Function4 nameEvaluator = graph.getPossibleRelatedValue2(typicalComposite, MOD.TypicalComposite_typicalNamingFunction); + return nameEvaluator; + } + + /** + * @param processor + * @param model + * @return + * @throws DatabaseException + */ + public static Collection findModelTypicals(RequestProcessor processor, final Resource model) throws DatabaseException { + return processor.syncRequest(new UniqueRead>() { + @Override + public Collection 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 syncExec(Consumer> runnable) throws DatabaseException { + final AtomicReference ref = new AtomicReference(); + final AtomicReference exc = new AtomicReference(); + final Semaphore sem = new Semaphore(0); + runnable.accept(new Procedure() { + @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. + * + *

+ * The created typical composite and diagram type are specified by the model + * using {@link ModelingResources#StructuralModel_HasTypicalCompositeBaseType} + * and {@link ModelingResources#StructuralModel_HasTypicalDiagramBaseType}. + * + *

+ * 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}. + * + *

+ * 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() { + + @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 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"