1 /*******************************************************************************
2 * Copyright (c) 2012 Association for Decentralized Information Management in
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.modeling.adapters;
14 import gnu.trove.set.hash.THashSet;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.List;
22 import org.simantics.databoard.Bindings;
23 import org.simantics.db.ReadGraph;
24 import org.simantics.db.Resource;
25 import org.simantics.db.common.NamedResource;
26 import org.simantics.db.common.request.PossibleIndexRoot;
27 import org.simantics.db.common.request.PossibleObjectWithType;
28 import org.simantics.db.common.utils.NameUtils;
29 import org.simantics.db.exception.DatabaseException;
30 import org.simantics.db.layer0.exception.VariableException;
31 import org.simantics.db.layer0.request.PossibleModel;
32 import org.simantics.db.layer0.variable.RVI;
33 import org.simantics.db.layer0.variable.Variable;
34 import org.simantics.db.layer0.variable.Variables;
35 import org.simantics.diagram.content.ConnectionUtil;
36 import org.simantics.diagram.stubs.DiagramResource;
37 import org.simantics.layer0.Layer0;
38 import org.simantics.modeling.ModelingResources;
39 import org.simantics.operation.Layer0X;
40 import org.simantics.scl.runtime.function.Function;
41 import org.simantics.structural.stubs.StructuralResource2;
42 import org.simantics.utils.ui.ErrorLogger;
45 * @author Tuukka Lehtonen
47 final class Removers {
49 public static ValidationResult validateFlagRemoval(ReadGraph graph, Resource flag) throws DatabaseException {
50 DiagramResource DIA = DiagramResource.getInstance(graph);
52 for (Resource connectionRelation : graph.getObjects(flag, DIA.IsLiftedAs)) {
53 ValidationResult result = validateConnectionRelationRemoval(graph, connectionRelation, null);
58 return new ValidationResult();
61 public static ValidationResult validateConnectionRelationRemoval(ReadGraph graph, Resource connectionRelation, Resource diagramConnectionRelation) throws DatabaseException {
62 Layer0 L0 = Layer0.getInstance(graph);
63 StructuralResource2 STR = StructuralResource2.getInstance(graph);
65 ValidationResult result = new ValidationResult();
67 // This is a connection point of a structural component type configuration.
68 String connectionRelationName = NameUtils.getSafeLabel(graph, connectionRelation);
69 result.connectionRelation = new NamedResource(connectionRelationName, connectionRelation);
70 if (diagramConnectionRelation != null) {
71 String diagramConnectionRelationName = NameUtils.getSafeLabel(graph, diagramConnectionRelation);
72 result.diagramConnectionRelation = new NamedResource(diagramConnectionRelationName, diagramConnectionRelation);
75 // 1. Get component type
76 Resource componentType = graph.sync( new PossibleObjectWithType(connectionRelation, L0.PartOf, STR.ComponentType) );
77 if (componentType == null)
79 String componentTypeName = graph.getPossibleRelatedValue(componentType, L0.HasName, Bindings.STRING);
80 if (componentTypeName == null)
82 result.componentType = new NamedResource(componentTypeName, componentType);
84 // 2. Find index roots that may contain references to this component type
85 Set<Resource> indexRoots = new THashSet<Resource>();
86 Resource indexRoot = graph.sync( new PossibleIndexRoot(componentType) );
87 if (indexRoot == null)
89 String indexRootName = graph.getPossibleRelatedValue(indexRoot, L0.HasName, Bindings.STRING);
90 if (indexRootName == null)
92 result.containingIndexRoot = new NamedResource(indexRootName, indexRoot);
94 Resource model = graph.sync( new PossibleModel(indexRoot) );
96 // Need to look for references in all models that use this shared library.
97 indexRoots.addAll( graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse) );
99 // The component type is in a model, other models can't reference it.
100 indexRoots.add(model);
103 // 3. Check whether this connection point is in use in any
104 // instances of this component type within the containing model.
105 for (Resource root : indexRoots) {
106 validateConnectionRelationRemovalForIndexRoot(graph, root, connectionRelation, diagramConnectionRelation, result);
112 private static void validateConnectionRelationRemovalForIndexRoot(ReadGraph graph, Resource root, Resource connectionRelation, Resource diagramConnectionRelation, ValidationResult result) throws DatabaseException {
113 String rootURI = graph.getPossibleURI(root);
117 Layer0 L0 = Layer0.getInstance(graph);
118 String rootName = graph.getPossibleRelatedValue(root, L0.HasName, Bindings.STRING);
119 if (rootName == null)
121 NamedResource namedRoot = new NamedResource(rootName, root);
123 @SuppressWarnings("rawtypes")
124 Function modules = graph.adapt(Layer0X.getInstance(graph).Dependencies, Function.class);
125 @SuppressWarnings("unchecked")
126 List<Map<String, Object>> rows = (List<Map<String, Object>>) modules.apply(graph, root, "Types:\"" + result.componentType.getName() + "\"");
130 ModelingResources MOD = ModelingResources.getInstance(graph);
131 StructuralResource2 STR = StructuralResource2.getInstance(graph);
133 for (Map<String, Object> row : rows) {
134 Resource component = (Resource) row.get("Resource");
135 if (graph.isInstanceOf(component, result.componentType.getResource())) {
136 String componentName = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING);
138 for (Resource connection : graph.getObjects(component, connectionRelation)) {
139 if (graph.isInstanceOf(connection, STR.Connection)) {
141 if (diagramConnectionRelation != null) {
142 // When diagram connection relation is defined, validate that
143 // exactly the specified diagram connection relation is being
144 // used and not some other relation from another symbol.
145 for (Resource element : graph.getObjects(component, MOD.ComponentToElement)) {
146 for (Resource diagramConnector : graph.getObjects(element, diagramConnectionRelation)) {
147 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, diagramConnector);
148 if (diagramConnection == null)
150 Resource correspondingConnection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
151 Resource correspondingConnectionSpecial = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnectionSpecial);
152 if (connection.equals(correspondingConnection) || connection.equals(correspondingConnectionSpecial)) {
153 addUse(graph, component, componentName, namedRoot, rootURI, result);
154 continue next_connection;
159 addUse(graph, component, componentName, namedRoot, rootURI, result);
168 private static boolean addUse(ReadGraph graph, Resource component, String componentName, NamedResource namedRoot, String rootURI, ValidationResult result) throws DatabaseException {
171 Variable variable = Variables.getVariable(graph, component);
172 if (!result.usedVariables.add(variable))
176 use.resource = component;
177 use.name = componentName;
178 use.variable = variable;
179 use.root = namedRoot;
180 uri = use.rootUri = use.variable.getURI(graph).replace(rootURI, "");
181 use.context = Variables.getPossibleContext(graph, use.variable);
182 if (use.context != null) {
183 use.path = Variables.getPossibleRVI2(graph, variable);
185 result.uses.add( use );
187 } catch (VariableException e) {
188 // Might happen with corrupt data, don't panic, just ignore.
189 ErrorLogger.defaultLogWarning("Connection relation removal validation ignored invalid connection to component " + uri, e);
194 public static String formatError(ReadGraph graph, ValidationResult result) throws DatabaseException {
195 StringBuilder sb = new StringBuilder();
196 sb.append("Cannot remove connection point '" + result.connectionRelation.getName() + "'\nfrom user component '" + result.componentType.getName() + "'.")
197 .append("\nIt is used in " + result.uses.size() + " instance(s):\n\n");
199 // See whether the uses contain references from other libraries/models
200 // than the containing index root.
201 boolean absoluteUris = false;
202 for (Use use : result.uses) {
203 if (!use.root.getResource().equals(result.containingIndexRoot.getResource())) {
209 for (Use use : result.uses) {
210 if (use.context != null) {
212 sb.append("/").append(use.root.getName()).append(use.rootUri);
214 sb.append(use.path.toPossibleString(graph, use.context));
218 sb.append("/").append(use.root.getName());
219 sb.append(use.rootUri);
223 return sb.toString();
226 public static class Use {
228 public Resource resource;
229 public Variable variable;
230 public Variable context;
232 public NamedResource root;
233 public String rootUri;
236 public static class ValidationResult {
237 public NamedResource containingIndexRoot;
238 public NamedResource componentType;
239 public NamedResource connectionRelation;
240 public NamedResource diagramConnectionRelation;
241 public Set<Variable> usedVariables = new THashSet<Variable>();
242 public Collection<Use> uses = new ArrayList<Use>();
244 public boolean inUse() {
245 return !uses.isEmpty();