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