--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2012 Association for Decentralized Information Management in\r
+ * 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.adapters;\r
+\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.NamedResource;\r
+import org.simantics.db.common.request.PossibleIndexRoot;\r
+import org.simantics.db.common.request.PossibleObjectWithType;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.exception.VariableException;\r
+import org.simantics.db.layer0.request.PossibleModel;\r
+import org.simantics.db.layer0.variable.RVI;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.layer0.variable.Variables;\r
+import org.simantics.diagram.content.ConnectionUtil;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.operation.Layer0X;\r
+import org.simantics.scl.runtime.function.Function;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+final class Removers {\r
+\r
+ public static ValidationResult validateFlagRemoval(ReadGraph graph, Resource flag) throws DatabaseException {\r
+ DiagramResource DIA = DiagramResource.getInstance(graph);\r
+\r
+ for (Resource connectionRelation : graph.getObjects(flag, DIA.IsLiftedAs)) {\r
+ ValidationResult result = validateConnectionRelationRemoval(graph, connectionRelation, null);\r
+ if (!result.inUse())\r
+ continue;\r
+ return result;\r
+ }\r
+ return new ValidationResult();\r
+ }\r
+\r
+ public static ValidationResult validateConnectionRelationRemoval(ReadGraph graph, Resource connectionRelation, Resource diagramConnectionRelation) throws DatabaseException {\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+\r
+ ValidationResult result = new ValidationResult();\r
+\r
+ // This is a connection point of a structural component type configuration.\r
+ String connectionRelationName = NameUtils.getSafeLabel(graph, connectionRelation);\r
+ result.connectionRelation = new NamedResource(connectionRelationName, connectionRelation);\r
+ if (diagramConnectionRelation != null) {\r
+ String diagramConnectionRelationName = NameUtils.getSafeLabel(graph, diagramConnectionRelation);\r
+ result.diagramConnectionRelation = new NamedResource(diagramConnectionRelationName, diagramConnectionRelation);\r
+ }\r
+\r
+ // 1. Get component type\r
+ Resource componentType = graph.sync( new PossibleObjectWithType(connectionRelation, L0.PartOf, STR.ComponentType) );\r
+ if (componentType == null)\r
+ return result;\r
+ String componentTypeName = graph.getPossibleRelatedValue(componentType, L0.HasName, Bindings.STRING);\r
+ if (componentTypeName == null)\r
+ return result;\r
+ result.componentType = new NamedResource(componentTypeName, componentType);\r
+\r
+ // 2. Find index roots that may contain references to this component type\r
+ Set<Resource> indexRoots = new THashSet<Resource>();\r
+ Resource indexRoot = graph.sync( new PossibleIndexRoot(componentType) );\r
+ if (indexRoot == null)\r
+ return result;\r
+ String indexRootName = graph.getPossibleRelatedValue(indexRoot, L0.HasName, Bindings.STRING);\r
+ if (indexRootName == null)\r
+ return result;\r
+ result.containingIndexRoot = new NamedResource(indexRootName, indexRoot);\r
+\r
+ Resource model = graph.sync( new PossibleModel(indexRoot) );\r
+ if (model == null) {\r
+ // Need to look for references in all models that use this shared library.\r
+ indexRoots.addAll( graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse) );\r
+ } else {\r
+ // The component type is in a model, other models can't reference it.\r
+ indexRoots.add(model);\r
+ }\r
+\r
+ // 3. Check whether this connection point is in use in any\r
+ // instances of this component type within the containing model.\r
+ for (Resource root : indexRoots) {\r
+ validateConnectionRelationRemovalForIndexRoot(graph, root, connectionRelation, diagramConnectionRelation, result);\r
+ }\r
+\r
+ return result;\r
+ }\r
+\r
+ private static void validateConnectionRelationRemovalForIndexRoot(ReadGraph graph, Resource root, Resource connectionRelation, Resource diagramConnectionRelation, ValidationResult result) throws DatabaseException {\r
+ String rootURI = graph.getPossibleURI(root);\r
+ if (rootURI == null)\r
+ return;\r
+\r
+ Layer0 L0 = Layer0.getInstance(graph);\r
+ String rootName = graph.getPossibleRelatedValue(root, L0.HasName, Bindings.STRING);\r
+ if (rootName == null)\r
+ return;\r
+ NamedResource namedRoot = new NamedResource(rootName, root);\r
+\r
+ @SuppressWarnings("rawtypes")\r
+ Function modules = graph.adapt(Layer0X.getInstance(graph).Dependencies, Function.class);\r
+ @SuppressWarnings("unchecked")\r
+ List<Map<String, Object>> rows = (List<Map<String, Object>>) modules.apply(graph, root, "Types:\"" + result.componentType.getName() + "\"");\r
+ if (rows.isEmpty())\r
+ return;\r
+\r
+ ModelingResources MOD = ModelingResources.getInstance(graph);\r
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+\r
+ for (Map<String, Object> row : rows) {\r
+ Resource component = (Resource) row.get("Resource");\r
+ if (graph.isInstanceOf(component, result.componentType.getResource())) {\r
+ String componentName = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING);\r
+ next_connection:\r
+ for (Resource connection : graph.getObjects(component, connectionRelation)) {\r
+ if (graph.isInstanceOf(connection, STR.Connection)) {\r
+\r
+ if (diagramConnectionRelation != null) {\r
+ // When diagram connection relation is defined, validate that\r
+ // exactly the specified diagram connection relation is being\r
+ // used and not some other relation from another symbol.\r
+ for (Resource element : graph.getObjects(component, MOD.ComponentToElement)) {\r
+ for (Resource diagramConnector : graph.getObjects(element, diagramConnectionRelation)) {\r
+ Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, diagramConnector);\r
+ if (diagramConnection == null)\r
+ continue;\r
+ Resource correspondingConnection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);\r
+ Resource correspondingConnectionSpecial = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnectionSpecial);\r
+ if (connection.equals(correspondingConnection) || connection.equals(correspondingConnectionSpecial)) {\r
+ addUse(graph, component, componentName, namedRoot, rootURI, result);\r
+ continue next_connection;\r
+ }\r
+ }\r
+ }\r
+ } else {\r
+ addUse(graph, component, componentName, namedRoot, rootURI, result);\r
+ }\r
+ }\r
+\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ private static boolean addUse(ReadGraph graph, Resource component, String componentName, NamedResource namedRoot, String rootURI, ValidationResult result) throws DatabaseException {\r
+ String uri = null;\r
+ try {\r
+ Variable variable = Variables.getVariable(graph, component);\r
+ if (!result.usedVariables.add(variable))\r
+ return false;\r
+\r
+ Use use = new Use();\r
+ use.resource = component;\r
+ use.name = componentName;\r
+ use.variable = variable;\r
+ use.root = namedRoot;\r
+ uri = use.rootUri = use.variable.getURI(graph).replace(rootURI, "");\r
+ use.context = Variables.getPossibleContext(graph, use.variable);\r
+ if (use.context != null) {\r
+ use.path = Variables.getPossibleRVI2(graph, variable);\r
+ }\r
+ result.uses.add( use );\r
+ return true;\r
+ } catch (VariableException e) {\r
+ // Might happen with corrupt data, don't panic, just ignore.\r
+ ErrorLogger.defaultLogWarning("Connection relation removal validation ignored invalid connection to component " + uri, e);\r
+ return false;\r
+ }\r
+ }\r
+\r
+ public static String formatError(ReadGraph graph, ValidationResult result) throws DatabaseException {\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append("Cannot remove connection point '" + result.connectionRelation.getName() + "'\nfrom user component '" + result.componentType.getName() + "'.")\r
+ .append("\nIt is used in " + result.uses.size() + " instance(s):\n\n");\r
+\r
+ // See whether the uses contain references from other libraries/models\r
+ // than the containing index root.\r
+ boolean absoluteUris = false;\r
+ for (Use use : result.uses) {\r
+ if (!use.root.getResource().equals(result.containingIndexRoot.getResource())) {\r
+ absoluteUris = true;\r
+ break;\r
+ }\r
+ }\r
+\r
+ for (Use use : result.uses) {\r
+ if (use.context != null) {\r
+ if (absoluteUris) {\r
+ sb.append("/").append(use.root.getName()).append(use.rootUri);\r
+ } else {\r
+ sb.append(use.path.toPossibleString(graph, use.context));\r
+ }\r
+ } else {\r
+ if (absoluteUris)\r
+ sb.append("/").append(use.root.getName());\r
+ sb.append(use.rootUri);\r
+ }\r
+ sb.append("\n");\r
+ }\r
+ return sb.toString();\r
+ }\r
+\r
+ public static class Use {\r
+ public String name;\r
+ public Resource resource;\r
+ public Variable variable;\r
+ public Variable context;\r
+ public RVI path;\r
+ public NamedResource root;\r
+ public String rootUri;\r
+ }\r
+\r
+ public static class ValidationResult {\r
+ public NamedResource containingIndexRoot;\r
+ public NamedResource componentType;\r
+ public NamedResource connectionRelation;\r
+ public NamedResource diagramConnectionRelation;\r
+ public Set<Variable> usedVariables = new THashSet<Variable>();\r
+ public Collection<Use> uses = new ArrayList<Use>();\r
+\r
+ public boolean inUse() {\r
+ return !uses.isEmpty();\r
+ }\r
+ }\r
+\r
+}\r