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.utils;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.List;
19 import org.simantics.databoard.Bindings;
20 import org.simantics.db.ReadGraph;
21 import org.simantics.db.Resource;
22 import org.simantics.db.common.NamedResource;
23 import org.simantics.db.common.request.PossibleIndexRoot;
24 import org.simantics.db.common.request.PossibleObjectWithType;
25 import org.simantics.db.common.utils.NameUtils;
26 import org.simantics.db.exception.DatabaseException;
27 import org.simantics.db.exception.VariableException;
28 import org.simantics.db.layer0.QueryIndexUtils;
29 import org.simantics.db.layer0.request.PossibleModel;
30 import org.simantics.db.layer0.variable.RVI;
31 import org.simantics.db.layer0.variable.Variable;
32 import org.simantics.db.layer0.variable.Variables;
33 import org.simantics.diagram.content.ConnectionUtil;
34 import org.simantics.diagram.stubs.DiagramResource;
35 import org.simantics.layer0.Layer0;
36 import org.simantics.modeling.ModelingResources;
37 import org.simantics.structural.stubs.StructuralResource2;
38 import org.simantics.utils.ui.ErrorLogger;
40 import gnu.trove.set.hash.THashSet;
43 * @author Tuukka Lehtonen
45 final public class RemoverUtils {
47 public static ValidationResult validateFlagRemoval(ReadGraph graph, Resource flag) throws DatabaseException {
48 DiagramResource DIA = DiagramResource.getInstance(graph);
50 for (Resource connectionRelation : graph.getObjects(flag, DIA.IsLiftedAs)) {
51 ValidationResult result = validateConnectionRelationRemoval(graph, connectionRelation, null);
56 return new ValidationResult();
59 public static ValidationResult validateConnectionRelationRemoval(ReadGraph graph, Resource connectionRelation, Resource diagramConnectionRelation) throws DatabaseException {
60 Layer0 L0 = Layer0.getInstance(graph);
61 StructuralResource2 STR = StructuralResource2.getInstance(graph);
63 ValidationResult result = new ValidationResult();
65 // This is a connection point of a structural component type configuration.
66 String connectionRelationName = NameUtils.getSafeLabel(graph, connectionRelation);
67 result.connectionRelation = new NamedResource(connectionRelationName, connectionRelation);
68 if (diagramConnectionRelation != null) {
69 String diagramConnectionRelationName = NameUtils.getSafeLabel(graph, diagramConnectionRelation);
70 result.diagramConnectionRelation = new NamedResource(diagramConnectionRelationName, diagramConnectionRelation);
73 // 1. Get component type
74 Resource componentType = graph.sync( new PossibleObjectWithType(connectionRelation, L0.PartOf, STR.ComponentType) );
75 if (componentType == null)
77 String componentTypeName = graph.getPossibleRelatedValue(componentType, L0.HasName, Bindings.STRING);
78 if (componentTypeName == null)
80 result.componentType = new NamedResource(componentTypeName, componentType);
82 // 2. Find index roots that may contain references to this component type
83 Set<Resource> indexRoots = new THashSet<Resource>();
84 Resource indexRoot = graph.sync( new PossibleIndexRoot(componentType) );
85 if (indexRoot == null)
87 String indexRootName = graph.getPossibleRelatedValue(indexRoot, L0.HasName, Bindings.STRING);
88 if (indexRootName == null)
90 result.containingIndexRoot = new NamedResource(indexRootName, indexRoot);
92 Resource model = graph.sync( new PossibleModel(indexRoot) );
94 // Need to look for references in all models that use this shared library.
95 indexRoots.addAll( graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse) );
97 // The component type is in a model, other models can't reference it.
98 indexRoots.add(model);
101 // 3. Check whether this connection point is in use in any
102 // instances of this component type within the containing model.
103 for (Resource root : indexRoots) {
104 validateConnectionRelationRemovalForIndexRoot(graph, root, connectionRelation, diagramConnectionRelation, result);
110 private static void validateConnectionRelationRemovalForIndexRoot(ReadGraph graph, Resource root, Resource connectionRelation, Resource diagramConnectionRelation, ValidationResult result) throws DatabaseException {
111 String rootURI = graph.getPossibleURI(root);
115 Layer0 L0 = Layer0.getInstance(graph);
116 String rootName = graph.getPossibleRelatedValue(root, L0.HasName, Bindings.STRING);
117 if (rootName == null)
119 NamedResource namedRoot = new NamedResource(rootName, root);
121 List<Resource> components = QueryIndexUtils.searchByTypeShallow(graph, root, result.componentType.getResource());
122 if (components.isEmpty())
125 ModelingResources MOD = ModelingResources.getInstance(graph);
126 StructuralResource2 STR = StructuralResource2.getInstance(graph);
128 for (Resource component : components) {
129 String componentName = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING);
131 for (Resource connection : graph.getObjects(component, connectionRelation)) {
132 if (graph.isInstanceOf(connection, STR.Connection)) {
134 if (diagramConnectionRelation != null) {
135 // When diagram connection relation is defined, validate that
136 // exactly the specified diagram connection relation is being
137 // used and not some other relation from another symbol.
138 for (Resource element : graph.getObjects(component, MOD.ComponentToElement)) {
139 for (Resource diagramConnector : graph.getObjects(element, diagramConnectionRelation)) {
140 Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, diagramConnector);
141 if (diagramConnection == null)
143 Resource correspondingConnection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection);
144 Resource correspondingConnectionSpecial = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnectionSpecial);
145 if (connection.equals(correspondingConnection) || connection.equals(correspondingConnectionSpecial)) {
146 addUse(graph, component, componentName, namedRoot, rootURI, result);
147 continue next_connection;
152 addUse(graph, component, componentName, namedRoot, rootURI, result);
159 private static boolean addUse(ReadGraph graph, Resource component, String componentName, NamedResource namedRoot, String rootURI, ValidationResult result) throws DatabaseException {
162 Variable variable = Variables.getVariable(graph, component);
163 if (!result.usedVariables.add(variable))
167 use.resource = component;
168 use.name = componentName;
169 use.variable = variable;
170 use.root = namedRoot;
171 uri = use.rootUri = use.variable.getURI(graph).replace(rootURI, "");
172 use.context = Variables.getPossibleContext(graph, use.variable);
173 if (use.context != null) {
174 use.path = Variables.getPossibleRVI2(graph, variable);
176 result.uses.add( use );
178 } catch (VariableException e) {
179 // Might happen with corrupt data, don't panic, just ignore.
180 ErrorLogger.defaultLogWarning("Connection relation removal validation ignored invalid connection to component " + uri, e);
185 public static String formatError(ReadGraph graph, ValidationResult result) throws DatabaseException {
186 StringBuilder sb = new StringBuilder();
187 sb.append("Cannot remove connection point '" + result.connectionRelation.getName() + "'\nfrom user component '" + result.componentType.getName() + "'.")
188 .append("\nIt is used in " + result.uses.size() + " instance(s):\n\n");
190 // See whether the uses contain references from other libraries/models
191 // than the containing index root.
192 boolean absoluteUris = false;
193 for (Use use : result.uses) {
194 if (!use.root.getResource().equals(result.containingIndexRoot.getResource())) {
200 for (Use use : result.uses) {
201 if (use.context != null) {
203 sb.append("/").append(use.root.getName()).append(use.rootUri);
205 sb.append(use.path.toPossibleString(graph, use.context));
209 sb.append("/").append(use.root.getName());
210 sb.append(use.rootUri);
214 return sb.toString();
217 public static class Use {
219 public Resource resource;
220 public Variable variable;
221 public Variable context;
223 public NamedResource root;
224 public String rootUri;
227 public static class ValidationResult {
228 public NamedResource containingIndexRoot;
229 public NamedResource componentType;
230 public NamedResource connectionRelation;
231 public NamedResource diagramConnectionRelation;
232 public Set<Variable> usedVariables = new THashSet<Variable>();
233 public Collection<Use> uses = new ArrayList<Use>();
235 public boolean inUse() {
236 return !uses.isEmpty();