| /***************************************************************************** |
| * Copyright (c) 2019 CEA LIST. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * CEA LIST - Initial API and implementation |
| *****************************************************************************/ |
| package org.eclipse.papyrus.moka.ssp.omsimulatorprofile.validation; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.validation.AbstractModelConstraint; |
| import org.eclipse.emf.validation.EMFEventType; |
| import org.eclipse.emf.validation.IValidationContext; |
| import org.eclipse.emf.validation.model.ConstraintStatus; |
| import org.eclipse.papyrus.moka.fmi.fmiprofile.FMIPort; |
| import org.eclipse.papyrus.moka.ssp.omsimulatorprofile.BusConnector; |
| import org.eclipse.papyrus.moka.ssp.omsimulatorprofile.OMSimulatorBus; |
| import org.eclipse.uml2.uml.ConnectableElement; |
| import org.eclipse.uml2.uml.Connector; |
| import org.eclipse.uml2.uml.ConnectorEnd; |
| import org.eclipse.uml2.uml.Port; |
| import org.eclipse.uml2.uml.Property; |
| import org.eclipse.uml2.uml.UMLPackage; |
| import org.eclipse.uml2.uml.util.UMLUtil; |
| |
| public class ConnectorConstraint extends AbstractModelConstraint { |
| |
| Set<Connector> firstRun = new HashSet<>(); |
| |
| @Override |
| public IStatus validate(IValidationContext ctx) { |
| |
| EMFEventType event = ctx.getEventType(); |
| EStructuralFeature feature = ctx.getFeature(); |
| Connector connector = (Connector) ctx.getTarget(); |
| |
| if ( ( feature == UMLPackage.eINSTANCE.getConnector_End() && firstRun.contains(connector))||event ==EMFEventType.NULL ){ |
| firstRun.remove(connector); |
| BusConnector busConnector = UMLUtil.getStereotypeApplication(connector, BusConnector.class); |
| if (busConnector != null) { |
| return checkBusConnector(busConnector, ctx); |
| } else { |
| return checkSimpleConnector(connector, ctx); |
| } |
| }else { |
| firstRun.add(connector); |
| return ctx.createSuccessStatus(); |
| } |
| |
| |
| } |
| |
| private IStatus checkSimpleConnector(Connector connector, IValidationContext ctx) { |
| |
| if (connector.getEnds().size()==2) { |
| |
| ConnectorEnd end1 = connector.getEnds().get(0); |
| ConnectorEnd end2 = connector.getEnds().get(1); |
| |
| |
| ConnectableElement role1 =end1.getRole(); |
| ConnectableElement role2 = end2.getRole(); |
| |
| ConnectableElement part1 = end1.getPartWithPort(); |
| ConnectableElement part2 = end2.getPartWithPort(); |
| |
| FMIPort fmiPort1 = UMLUtil.getStereotypeApplication(role1, FMIPort.class); |
| FMIPort fmiPort2 = UMLUtil.getStereotypeApplication(role2, FMIPort.class); |
| |
| |
| if (role1 instanceof Port && role2 instanceof Port && part1 instanceof Property && part2 instanceof Property |
| && fmiPort1 != null && fmiPort2 != null) { |
| |
| Port port1 = (Port) role1; |
| Port port2 = (Port) role2; |
| |
| |
| List<IStatus> problems = new ArrayList<>(); |
| |
| IStatus problem = checkPortTypes(ctx, connector, part1, port1, part2, port2); |
| if (problem != null) { |
| problems.add(problem); |
| } |
| |
| problem = checkPortDirections(ctx, connector, part1, port1,fmiPort1 ,part2, port2, fmiPort2); |
| if (problem != null) { |
| problems.add(problem); |
| } |
| |
| |
| return problems.isEmpty()? ctx.createSuccessStatus() : |
| ConstraintStatus.createMultiStatus(ctx, problems); |
| } |
| |
| } |
| |
| |
| return ctx.createSuccessStatus(); |
| } |
| |
| String getPortName(ConnectableElement part, Port port) { |
| return part.getName()+"." + port.getName(); |
| } |
| |
| |
| private IStatus checkPortTypes(IValidationContext ctx, Connector connector, ConnectableElement part1, Port port1, ConnectableElement part2, Port port2) { |
| if (port1.getType() != port2.getType()) { String message = "{0} and {1} should have same types"; |
| return ConstraintStatus.createStatus(ctx, Arrays.asList(part1, port1, part1, port2),message, getPortName(part1, port1), getPortName(part2, port2)); |
| } |
| return null; |
| } |
| |
| private IStatus checkPortDirections(IValidationContext ctx, Connector connector, ConnectableElement part1, Port port1, FMIPort fmiPort1, ConnectableElement part2, Port port2, FMIPort fmiPort2) { |
| if (fmiPort1.getDirection() == fmiPort2.getDirection()) { |
| String message = "{0} and {1} should have opposite directions"; |
| return ConstraintStatus.createStatus(ctx, Arrays.asList(part1, port1, part1, port2),message, getPortName(part1, port1), getPortName(part2, port2)); |
| } |
| return null; |
| } |
| |
| |
| private IStatus checkBusConnector(BusConnector busConnector, IValidationContext ctx) { |
| Connector connector = busConnector.getBase_Connector(); |
| |
| if (connector.getEnds().size()==2) { |
| |
| ConnectorEnd end1 = connector.getEnds().get(0); |
| ConnectorEnd end2 = connector.getEnds().get(1); |
| |
| ConnectableElement role1 =end1.getRole(); |
| ConnectableElement role2 = end2.getRole(); |
| |
| ConnectableElement part1 = end1.getPartWithPort(); |
| ConnectableElement part2 = end2.getPartWithPort(); |
| |
| |
| |
| if (role1 instanceof Port && role2 instanceof Port && part1 instanceof Property && part2 instanceof Property) { |
| |
| Port busPort1 = (Port) role1; |
| Port busPort2 = (Port) role2; |
| |
| IStatus problem = checkBusSize(ctx, connector, busConnector, part1, busPort1, part2, busPort2); |
| |
| if (problem != null) { |
| return problem; |
| } |
| List<IStatus> problems = new ArrayList<>(); |
| |
| for (int i = 0 ; i< busConnector.getEnd1Signals().size(); i++) { |
| Port port1 = busConnector.getEnd1Signals().get(i); |
| Port port2 = busConnector.getEnd2Signals().get(i); |
| |
| FMIPort fmiPort1 = UMLUtil.getStereotypeApplication(port1, FMIPort.class); |
| FMIPort fmiPort2 = UMLUtil.getStereotypeApplication(port2, FMIPort.class); |
| |
| problem = checkPortTypes(ctx, connector, part1, port1, part2, port2); |
| if (problem != null) { |
| problems.add(problem); |
| } |
| |
| if (fmiPort1 != null && fmiPort2!= null) { |
| problem = checkPortDirections(ctx, connector, part1, port1,fmiPort1 ,part2, port2, fmiPort2); |
| if (problem != null) { |
| problems.add(problem); |
| } |
| } |
| |
| |
| } |
| |
| |
| |
| return problems.isEmpty()? ctx.createSuccessStatus() : |
| ConstraintStatus.createMultiStatus(ctx, problems); |
| } |
| |
| } |
| |
| |
| return ctx.createSuccessStatus(); |
| } |
| |
| private IStatus checkBusSize(IValidationContext ctx, Connector connector, BusConnector busConnector, |
| ConnectableElement part1, Port busPort1, ConnectableElement part2, Port busPort2) { |
| if (busConnector.getEnd1Signals().size() != busConnector.getEnd2Signals().size()) { |
| String message = "{0} and {1} busses should have same size"; |
| return ConstraintStatus.createStatus(ctx, Arrays.asList(part1, busPort1, part1, busPort2),message, getPortName(part1, busPort1), getPortName(part2, busPort2)); |
| } |
| return null; |
| } |
| |
| |
| |
| } |