/******************************************************************************* * Copyright (c) 2012 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.modeling.adapters; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.common.NamedResource; import org.simantics.db.common.request.PossibleIndexRoot; import org.simantics.db.common.request.PossibleObjectWithType; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.VariableException; import org.simantics.db.layer0.QueryIndexUtils; import org.simantics.db.layer0.request.PossibleModel; import org.simantics.db.layer0.variable.RVI; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; import org.simantics.diagram.content.ConnectionUtil; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.utils.ui.ErrorLogger; import gnu.trove.set.hash.THashSet; /** * @author Tuukka Lehtonen */ final class Removers { public static ValidationResult validateFlagRemoval(ReadGraph graph, Resource flag) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); for (Resource connectionRelation : graph.getObjects(flag, DIA.IsLiftedAs)) { ValidationResult result = validateConnectionRelationRemoval(graph, connectionRelation, null); if (!result.inUse()) continue; return result; } return new ValidationResult(); } public static ValidationResult validateConnectionRelationRemoval(ReadGraph graph, Resource connectionRelation, Resource diagramConnectionRelation) throws DatabaseException { Layer0 L0 = Layer0.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); ValidationResult result = new ValidationResult(); // This is a connection point of a structural component type configuration. String connectionRelationName = NameUtils.getSafeLabel(graph, connectionRelation); result.connectionRelation = new NamedResource(connectionRelationName, connectionRelation); if (diagramConnectionRelation != null) { String diagramConnectionRelationName = NameUtils.getSafeLabel(graph, diagramConnectionRelation); result.diagramConnectionRelation = new NamedResource(diagramConnectionRelationName, diagramConnectionRelation); } // 1. Get component type Resource componentType = graph.sync( new PossibleObjectWithType(connectionRelation, L0.PartOf, STR.ComponentType) ); if (componentType == null) return result; String componentTypeName = graph.getPossibleRelatedValue(componentType, L0.HasName, Bindings.STRING); if (componentTypeName == null) return result; result.componentType = new NamedResource(componentTypeName, componentType); // 2. Find index roots that may contain references to this component type Set indexRoots = new THashSet(); Resource indexRoot = graph.sync( new PossibleIndexRoot(componentType) ); if (indexRoot == null) return result; String indexRootName = graph.getPossibleRelatedValue(indexRoot, L0.HasName, Bindings.STRING); if (indexRootName == null) return result; result.containingIndexRoot = new NamedResource(indexRootName, indexRoot); Resource model = graph.sync( new PossibleModel(indexRoot) ); if (model == null) { // Need to look for references in all models that use this shared library. indexRoots.addAll( graph.getObjects(indexRoot, L0.IsLinkedTo_Inverse) ); } else { // The component type is in a model, other models can't reference it. indexRoots.add(model); } // 3. Check whether this connection point is in use in any // instances of this component type within the containing model. for (Resource root : indexRoots) { validateConnectionRelationRemovalForIndexRoot(graph, root, connectionRelation, diagramConnectionRelation, result); } return result; } private static void validateConnectionRelationRemovalForIndexRoot(ReadGraph graph, Resource root, Resource connectionRelation, Resource diagramConnectionRelation, ValidationResult result) throws DatabaseException { String rootURI = graph.getPossibleURI(root); if (rootURI == null) return; Layer0 L0 = Layer0.getInstance(graph); String rootName = graph.getPossibleRelatedValue(root, L0.HasName, Bindings.STRING); if (rootName == null) return; NamedResource namedRoot = new NamedResource(rootName, root); List components = QueryIndexUtils.searchByTypeShallow(graph, root, result.componentType.getResource()); if (components.isEmpty()) return; ModelingResources MOD = ModelingResources.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); for (Resource component : components) { String componentName = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING); next_connection: for (Resource connection : graph.getObjects(component, connectionRelation)) { if (graph.isInstanceOf(connection, STR.Connection)) { if (diagramConnectionRelation != null) { // When diagram connection relation is defined, validate that // exactly the specified diagram connection relation is being // used and not some other relation from another symbol. for (Resource element : graph.getObjects(component, MOD.ComponentToElement)) { for (Resource diagramConnector : graph.getObjects(element, diagramConnectionRelation)) { Resource diagramConnection = ConnectionUtil.tryGetConnection(graph, diagramConnector); if (diagramConnection == null) continue; Resource correspondingConnection = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnection); Resource correspondingConnectionSpecial = graph.getPossibleObject(diagramConnection, MOD.DiagramConnectionToConnectionSpecial); if (connection.equals(correspondingConnection) || connection.equals(correspondingConnectionSpecial)) { addUse(graph, component, componentName, namedRoot, rootURI, result); continue next_connection; } } } } else { addUse(graph, component, componentName, namedRoot, rootURI, result); } } } } } private static boolean addUse(ReadGraph graph, Resource component, String componentName, NamedResource namedRoot, String rootURI, ValidationResult result) throws DatabaseException { String uri = null; try { Variable variable = Variables.getVariable(graph, component); if (!result.usedVariables.add(variable)) return false; Use use = new Use(); use.resource = component; use.name = componentName; use.variable = variable; use.root = namedRoot; uri = use.rootUri = use.variable.getURI(graph).replace(rootURI, ""); use.context = Variables.getPossibleContext(graph, use.variable); if (use.context != null) { use.path = Variables.getPossibleRVI2(graph, variable); } result.uses.add( use ); return true; } catch (VariableException e) { // Might happen with corrupt data, don't panic, just ignore. ErrorLogger.defaultLogWarning("Connection relation removal validation ignored invalid connection to component " + uri, e); return false; } } public static String formatError(ReadGraph graph, ValidationResult result) throws DatabaseException { StringBuilder sb = new StringBuilder(); sb.append("Cannot remove connection point '" + result.connectionRelation.getName() + "'\nfrom user component '" + result.componentType.getName() + "'.") .append("\nIt is used in " + result.uses.size() + " instance(s):\n\n"); // See whether the uses contain references from other libraries/models // than the containing index root. boolean absoluteUris = false; for (Use use : result.uses) { if (!use.root.getResource().equals(result.containingIndexRoot.getResource())) { absoluteUris = true; break; } } for (Use use : result.uses) { if (use.context != null) { if (absoluteUris) { sb.append("/").append(use.root.getName()).append(use.rootUri); } else { sb.append(use.path.toPossibleString(graph, use.context)); } } else { if (absoluteUris) sb.append("/").append(use.root.getName()); sb.append(use.rootUri); } sb.append("\n"); } return sb.toString(); } public static class Use { public String name; public Resource resource; public Variable variable; public Variable context; public RVI path; public NamedResource root; public String rootUri; } public static class ValidationResult { public NamedResource containingIndexRoot; public NamedResource componentType; public NamedResource connectionRelation; public NamedResource diagramConnectionRelation; public Set usedVariables = new THashSet(); public Collection uses = new ArrayList(); public boolean inUse() { return !uses.isEmpty(); } } }