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.exception.VariableException;
31 import org.simantics.db.layer0.genericrelation.IndexQueries;
32 import org.simantics.db.layer0.request.PossibleModel;
33 import org.simantics.db.layer0.variable.RVI;
34 import org.simantics.db.layer0.variable.Variable;
35 import org.simantics.db.layer0.variable.Variables;
36 import org.simantics.diagram.content.ConnectionUtil;
37 import org.simantics.diagram.stubs.DiagramResource;
38 import org.simantics.layer0.Layer0;
39 import org.simantics.modeling.ModelingResources;
40 import org.simantics.operation.Layer0X;
41 import org.simantics.scl.runtime.function.Function;
42 import org.simantics.structural.stubs.StructuralResource2;
43 import org.simantics.utils.ui.ErrorLogger;
46 * @author Tuukka Lehtonen
48 final class Removers {
50 public static ValidationResult validateFlagRemoval(ReadGraph graph, Resource flag) throws DatabaseException {
51 DiagramResource DIA = DiagramResource.getInstance(graph);
53 for (Resource connectionRelation : graph.getObjects(flag, DIA.IsLiftedAs)) {
54 ValidationResult result = validateConnectionRelationRemoval(graph, connectionRelation, null);
59 return new ValidationResult();
62 public static ValidationResult validateConnectionRelationRemoval(ReadGraph graph, Resource connectionRelation, Resource diagramConnectionRelation) throws DatabaseException {
63 Layer0 L0 = Layer0.getInstance(graph);
64 StructuralResource2 STR = StructuralResource2.getInstance(graph);
66 ValidationResult result = new ValidationResult();
68 // This is a connection point of a structural component type configuration.
69 String connectionRelationName = NameUtils.getSafeLabel(graph, connectionRelation);
70 result.connectionRelation = new NamedResource(connectionRelationName, connectionRelation);
71 if (diagramConnectionRelation != null) {
72 String diagramConnectionRelationName = NameUtils.getSafeLabel(graph, diagramConnectionRelation);
73 result.diagramConnectionRelation = new NamedResource(diagramConnectionRelationName, diagramConnectionRelation);
76 // 1. Get component type
77 Resource componentType = graph.sync( new PossibleObjectWithType(connectionRelation, L0.PartOf, STR.ComponentType) );
78 if (componentType == null)
80 String componentTypeName = graph.getPossibleRelatedValue(componentType, L0.HasName, Bindings.STRING);
81 if (componentTypeName == null)
83 result.componentType = new NamedResource(componentTypeName, componentType);
85 // 2. Find index roots that may contain references to this component type
86 Set<Resource> indexRoots = new THashSet<Resource>();
87 Resource indexRoot = graph.sync( new PossibleIndexRoot(componentType) );
88 if (indexRoot == null)
90 String indexRootName = graph.getPossibleRelatedValue(indexRoot, L0.HasName, Bindings.STRING);
91 if (indexRootName == null)
93 result.containingIndexRoot = new NamedResource(indexRootName, indexRoot);
95 Resource model = graph.sync( new PossibleModel(indexRoot) );
97 // Need to look for references in all models that use this shared library.
98 indexRoots.addAll( graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse) );
100 // The component type is in a model, other models can't reference it.
101 indexRoots.add(model);
104 // 3. Check whether this connection point is in use in any
105 // instances of this component type within the containing model.
106 for (Resource root : indexRoots) {
107 validateConnectionRelationRemovalForIndexRoot(graph, root, connectionRelation, diagramConnectionRelation, result);
113 private static void validateConnectionRelationRemovalForIndexRoot(ReadGraph graph, Resource root, Resource connectionRelation, Resource diagramConnectionRelation, ValidationResult result) throws DatabaseException {
114 String rootURI = graph.getPossibleURI(root);
118 Layer0 L0 = Layer0.getInstance(graph);
119 String rootName = graph.getPossibleRelatedValue(root, L0.HasName, Bindings.STRING);
120 if (rootName == null)
122 NamedResource namedRoot = new NamedResource(rootName, root);
124 @SuppressWarnings("rawtypes")
125 Function modules = graph.adapt(Layer0X.getInstance(graph).Dependencies, Function.class);
126 @SuppressWarnings("unchecked")
127 List<Map<String, Object>> rows = (List<Map<String, Object>>) modules.apply(graph, root, "Types:" + IndexQueries.quoteTerm(result.componentType.getName()));
131 ModelingResources MOD = ModelingResources.getInstance(graph);
132 StructuralResource2 STR = StructuralResource2.getInstance(graph);
134 for (Map<String, Object> row : rows) {
135 Resource component = (Resource) row.get("Resource");
136 if (graph.isInstanceOf(component, result.componentType.getResource())) {
137 String componentName = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING);
139 for (Resource connection : graph.getObjects(component, connectionRelation)) {
140 if (graph.isInstanceOf(connection, STR.Connection)) {
142 if (diagramConnectionRelation != null) {
143 // When diagram connection relation is defined, validate that
144 // exactly the specified diagram connection relation is being
145 // used and not some other relation from another symbol.
146 for (Resource element : graph.getObjects(component, MOD.ComponentToElement)) {
147 for (Resource diagramConnector : graph.getObjects(element, diagramConnectionRelation)) {
148 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, diagramConnector);
149 if (diagramConnection == null)
151 Resource correspondingConnection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
152 Resource correspondingConnectionSpecial = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnectionSpecial);
153 if (connection.equals(correspondingConnection) || connection.equals(correspondingConnectionSpecial)) {
154 addUse(graph, component, componentName, namedRoot, rootURI, result);
155 continue next_connection;
160 addUse(graph, component, componentName, namedRoot, rootURI, result);
169 private static boolean addUse(ReadGraph graph, Resource component, String componentName, NamedResource namedRoot, String rootURI, ValidationResult result) throws DatabaseException {
172 Variable variable = Variables.getVariable(graph, component);
173 if (!result.usedVariables.add(variable))
177 use.resource = component;
178 use.name = componentName;
179 use.variable = variable;
180 use.root = namedRoot;
181 uri = use.rootUri = use.variable.getURI(graph).replace(rootURI, "");
182 use.context = Variables.getPossibleContext(graph, use.variable);
183 if (use.context != null) {
184 use.path = Variables.getPossibleRVI2(graph, variable);
186 result.uses.add( use );
188 } catch (VariableException e) {
189 // Might happen with corrupt data, don't panic, just ignore.
190 ErrorLogger.defaultLogWarning("Connection relation removal validation ignored invalid connection to component " + uri, e);
195 public static String formatError(ReadGraph graph, ValidationResult result) throws DatabaseException {
196 StringBuilder sb = new StringBuilder();
197 sb.append("Cannot remove connection point '" + result.connectionRelation.getName() + "'\nfrom user component '" + result.componentType.getName() + "'.")
198 .append("\nIt is used in " + result.uses.size() + " instance(s):\n\n");
200 // See whether the uses contain references from other libraries/models
201 // than the containing index root.
202 boolean absoluteUris = false;
203 for (Use use : result.uses) {
204 if (!use.root.getResource().equals(result.containingIndexRoot.getResource())) {
210 for (Use use : result.uses) {
211 if (use.context != null) {
213 sb.append("/").append(use.root.getName()).append(use.rootUri);
215 sb.append(use.path.toPossibleString(graph, use.context));
219 sb.append("/").append(use.root.getName());
220 sb.append(use.rootUri);
224 return sb.toString();
227 public static class Use {
229 public Resource resource;
230 public Variable variable;
231 public Variable context;
233 public NamedResource root;
234 public String rootUri;
237 public static class ValidationResult {
238 public NamedResource containingIndexRoot;
239 public NamedResource componentType;
240 public NamedResource connectionRelation;
241 public NamedResource diagramConnectionRelation;
242 public Set<Variable> usedVariables = new THashSet<Variable>();
243 public Collection<Use> uses = new ArrayList<Use>();
245 public boolean inUse() {
246 return !uses.isEmpty();