/******************************************************************************* * Copyright (c) 2007, 2014 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 * Semantum Oy - #5290 *******************************************************************************/ package org.simantics.modeling.rules; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.modeling.ModelingResources; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.structural2.modelingRules.AbstractModelingRules; import org.simantics.structural2.modelingRules.CPConnection; import org.simantics.structural2.modelingRules.CPConnectionJoin; import org.simantics.structural2.modelingRules.CPIgnore; import org.simantics.structural2.modelingRules.CPTerminal; import org.simantics.structural2.modelingRules.ConnectionJudgement; import org.simantics.structural2.modelingRules.IAttachmentRelationMap; import org.simantics.structural2.modelingRules.IConnectionPoint; import org.simantics.structural2.modelingRules.IModelingRules; import org.simantics.structural2.modelingRules.Policy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MappedModelingRules extends AbstractModelingRules { private static final Logger LOGGER = LoggerFactory.getLogger(MappedModelingRules.class); IModelingRules baseRules; IMapping mapping; public MappedModelingRules(IModelingRules baseRules, IMapping mapping) { super(); this.baseRules = baseRules; this.mapping = mapping; } public MappedModelingRules(ReadGraph g, IModelingRules baseRules) throws DatabaseException { this(baseRules, new Mapping(g)); } @Override public boolean canPopulate(ReadGraph g, Resource componentType) throws DatabaseException { Resource mappedComponentType = mapping.mapComponentType(g, componentType); if(mappedComponentType == null) return false; return baseRules.canPopulate(g, mappedComponentType); } @Override public void setConnectionType(WriteGraph g, Resource connection, Resource connectionType) throws DatabaseException { StructuralResource2 sr = StructuralResource2.getInstance(g); DiagramResource DIA = DiagramResource.getInstance(g); ModelingResources MOD = ModelingResources.getInstance(g); if(Policy.DEBUG_STANDARD_MODELING_RULES) LOGGER.info("setConnectionType(" + NameUtils.getSafeName(g, connection) + ", " + NameUtils.getSafeName(g, connectionType) + ")"); RelatedDiagramConnections rdc = new RelatedDiagramConnections(g); rdc.addConnection(connection); for(Resource c : rdc.connections) { g.deny(c, sr.HasConnectionType); g.claim(c, sr.HasConnectionType, null, connectionType); } // Fix MOD.HasConnectionMappingSpecification in output connector(s). if (!rdc.outputConnectors.isEmpty()) { Resource requiredConnectionMappingSpecification = g.getPossibleObject(connectionType, MOD.ConnectionTypeToConnectionMappingSpecification); for (Resource connector : rdc.outputConnectors) { for (Statement connects : g.getStatements(connector, sr.Connects)) { if (g.isInstanceOf(connects.getObject(), DIA.Connection)) continue; Resource dcp = g.getPossibleInverse(connects.getPredicate()); if (dcp != null) { Resource cp = g.getPossibleObject(dcp, MOD.DiagramConnectionRelationToConnectionRelation); if (cp != null) { g.deny(connector, MOD.HasConnectionMappingSpecification); if (requiredConnectionMappingSpecification != null && g.hasStatement(cp, MOD.NeedsConnectionMappingSpecification)) { g.claim(connector, MOD.HasConnectionMappingSpecification, requiredConnectionMappingSpecification); } } } } } } } class MappedAttachmentRelationMap implements IAttachmentRelationMap { IAttachmentRelationMap baseMap; public MappedAttachmentRelationMap(IAttachmentRelationMap baseMap) { this.baseMap = baseMap; } @Override public Resource get(ReadGraph g, CPTerminal cp) throws DatabaseException { IConnectionPoint mcp = mapping.mapConnectionPoint(g, cp); if(mcp instanceof CPTerminal) return baseMap.get(g, (CPTerminal)mcp); else return null; } } private ArrayList getMappedConnectionPoints(ReadGraph g, Collection connectionPoints) throws DatabaseException { // Map connection points to configuration ArrayList mappedConnectionPoints = new ArrayList(connectionPoints.size()); // Map connection points to configuration for(IConnectionPoint cp : connectionPoints) { if(cp == null) throw new IllegalArgumentException("Null connection point encountered."); if(Policy.DEBUG_STANDARD_MODELING_RULES) LOGGER.info("Mapping CP: " + cp.toString(g)); int mcps = mapping.mapToConnectionPoints(g, cp, mappedConnectionPoints); if(mcps > 0) { if(Policy.DEBUG_STANDARD_MODELING_RULES) for (IConnectionPoint mcpt : mappedConnectionPoints.subList(mappedConnectionPoints.size()-mcps, mappedConnectionPoints.size())) LOGGER.info("Mapped CP: " + mcpt.toString(g)); } else { if(cp instanceof CPTerminal) { // TODO move this logic elsewhere CPTerminal terminal = (CPTerminal)cp; DiagramResource dr = DiagramResource.getInstance(g); if(terminal.component != null && g.isInstanceOf(terminal.component, dr.Flag)) { if(g.hasStatement(terminal.component, dr.Flag_ConnectionPoint)) return null; for(Resource join : g.getObjects(terminal.component, dr.FlagIsJoinedBy)) mappedConnectionPoints.add(new CPConnectionJoin(join)); Resource isLiftedAs = g.getPossibleObject(terminal.component, dr.IsLiftedAs); if (isLiftedAs != null) { // This is a lifted flag in a structural configuration. mappedConnectionPoints.add(new CPTerminal(terminal.component, isLiftedAs)); } else { mappedConnectionPoints.add(terminal); } } } else if (cp instanceof CPConnection) { // Do nothing, because ignored connection points are not // meant to affect modelling rules in any way. //System.out.println("Non-mappable connection " + cp.toString(g)); } else if (cp instanceof CPIgnore) { // Do nothing, because ignored connection points are not // meant to affect modelling rules in any way. // FIXME: this is maybe a bit of a hack. //System.out.println("Ignoring " + cp.toString(g)); } else return null; } } return mappedConnectionPoints; } @Override public ConnectionJudgement judgeConnection(ReadGraph g, Collection connectionPoints) throws DatabaseException { ArrayList mappedConnectionPoints = getMappedConnectionPoints(g, connectionPoints); if(mappedConnectionPoints == null) return ConnectionJudgement.ILLEGAL; // Judge mapped connection ConnectionJudgement judgement = baseRules.judgeConnection(g, mappedConnectionPoints); // Inverse map attachment relations if(judgement.attachmentRelations != null) judgement.attachmentRelations = new MappedAttachmentRelationMap(judgement.attachmentRelations); return judgement; } @Override public Resource computeConnectionType(ReadGraph g, Collection connectionPoints) throws DatabaseException { ArrayList mappedConnectionPoints = getMappedConnectionPoints(g, connectionPoints); if(mappedConnectionPoints == null) return null; return baseRules.computeConnectionType(g, mappedConnectionPoints); } @Override public IAttachmentRelationMap getAttachmentRelations(ReadGraph g, Resource connection) throws DatabaseException { Resource mappedConnection = mapping.mapConnection(g, connection); if(mappedConnection == null) LOGGER.warn("Connection mapped from " + NameUtils.getSafeName(g, connection, true) + " is null"); return new MappedAttachmentRelationMap( baseRules.getAttachmentRelations(g, mappedConnection) ); } @Override public Set resolveTerminals(ReadGraph g, Collection connectionPoints) throws DatabaseException { Set terminals = new HashSet(); StructuralResource2 STR = StructuralResource2.getInstance(g); DiagramResource DIA = DiagramResource.getInstance(g); for(IConnectionPoint cp : connectionPoints) { //System.out.println(this + ": translate connection point: " + cp.toString(g)); if(cp instanceof CPTerminal) terminals.add((CPTerminal)cp); else if(cp instanceof CPConnection) { CPConnection connection = (CPConnection)cp; for (Resource connector : g.getObjects(connection.connection, DIA.HasConnector)) { for (Statement stat : g.getStatements(connector, STR.Connects)) { if(stat.getObject().equals(connection.connection)) continue; terminals.add(new CPTerminal(stat.getObject(), g.getInverse(stat.getPredicate()))); } } } else throw new IllegalArgumentException("Connection point " + cp + " encountered."); } return terminals; } }