blob: 0e1b924bf32418ac9aeb2f1d15d392a558c2efdf [file] [log] [blame]
/*****************************************************************************
* 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;
}
}