Bug 510315: [UML-RT] UML specific implementation for state machines More extensive notification support in the façade metamodel, beyond what is required to support the Capsule and Protocol properties in the property sheet UI. https://bugs.eclipse.org/bugs/show_bug.cgi?id=510315 Change-Id: I366b195f9d7acb86c4c5bc5729a8b412205b7202
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/UMLRTCapsulePartKind.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/UMLRTCapsulePartKind.java index 4d0ed4f..1b09ad9 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/UMLRTCapsulePartKind.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/UMLRTCapsulePartKind.java
@@ -17,6 +17,8 @@ import java.util.List; import org.eclipse.emf.common.util.Enumerator; +import org.eclipse.uml2.uml.AggregationKind; +import org.eclipse.uml2.uml.LiteralUnlimitedNatural; /** * <!-- begin-user-doc --> @@ -316,6 +318,89 @@ } /** + * Computes the kind that is like me but for capsule-parts of the given {@code required} kind. + * + * @param required + * the requireness kind from which to derive a new capsule-part kind + * @return the new capsule-part kind, which may be {@link #NULL} if this value of {@code required} + * does not make sense with the other attributes that I imply + */ + public UMLRTCapsulePartKind setRequired(boolean required) { + if (required == isRequired()) { + return this; + } else { + switch (this) { + case OPTIONAL: + return FIXED; + case FIXED: + return OPTIONAL; + case PLUG_IN: + // We don't consider aggregation if the multiplicity is required + return FIXED; + default: + return NULL; + } + } + } + + /** + * Computes the kind that is like me but for capsule-parts of the given {@code composite} kind. + * + * @param composite + * the compositeness kind from which to derive a new capsule-part kind + * @return the new capsule-part kind, which may be {@link #NULL} if this value of {@code composite} + * does not make sense with the other attributes that I imply + */ + public UMLRTCapsulePartKind setComposite(boolean composite) { + if (composite == isComposite()) { + return this; + } else { + switch (this) { + case OPTIONAL: + return PLUG_IN; + case PLUG_IN: + return OPTIONAL; + default: + return NULL; + } + } + } + + /** + * Computes the kind of a capsule-part by its attributes. + * + * @param lowerBound + * the capsule-part's lower bound + * @param upperBound + * the capsule-part's upper bound + * @param aggregation + * the capsule-part's aggregation + * + * @return the capsule-part kind, or {@link #NULL} if the specific attributes make no sense together + */ + public static UMLRTCapsulePartKind get(int lowerBound, int upperBound, AggregationKind aggregation) { + UMLRTCapsulePartKind result = UMLRTCapsulePartKind.NULL; + + if ((lowerBound > 0) && (upperBound > 0)) { + result = FIXED; + } else if ((lowerBound == 0) || (upperBound == LiteralUnlimitedNatural.UNLIMITED)) { + switch (aggregation) { + case COMPOSITE_LITERAL: + result = OPTIONAL; + break; + case SHARED_LITERAL: + result = PLUG_IN; + break; + default: + // Pass + break; + } + } + + return result; + } + + /** * Returns the literal value of the enumerator, which is its string representation. * <!-- begin-user-doc --> * <!-- end-user-doc -->
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/UMLRTPortKind.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/UMLRTPortKind.java index eb4f6a0..eb844c5 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/UMLRTPortKind.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/UMLRTPortKind.java
@@ -426,6 +426,138 @@ } /** + * Computes the kind that is like me but for ports of the given {@code service} kind. + * + * @param service + * the service kind from which to derive a new port kind + * @return the new port kind, which may be {@link #NULL} if this value of {@code service} + * does not make sense with the other attributes that I imply + */ + public UMLRTPortKind setService(boolean service) { + if (service == isService()) { + return this; + } else { + switch (this) { + case EXTERNAL_BEHAVIOR: + return INTERNAL_BEHAVIOR; + case INTERNAL_BEHAVIOR: + return EXTERNAL_BEHAVIOR; + case SPP: + return SAP; + case SAP: + return SPP; + default: + return NULL; + } + } + } + + /** + * Computes the kind that is like me but for ports of the given {@code behavior} kind. + * + * @param behavior + * the behavior kind from which to derive a new port kind + * @return the new port kind, which may be {@link #NULL} if this value of {@code behavior} + * does not make sense with the other attributes that I imply + */ + public UMLRTPortKind setBehavior(boolean behavior) { + if (behavior == isBehavior()) { + return this; + } else { + switch (this) { + case EXTERNAL_BEHAVIOR: + return RELAY; + case RELAY: + return EXTERNAL_BEHAVIOR; + default: + return NULL; + } + } + } + + /** + * Computes the kind that is like me but for ports of the given {@code wired} kind. + * + * @param wired + * the wiredness kind from which to derive a new port kind + * @return the new port kind, which may be {@link #NULL} if this value of {@code wired} + * does not make sense with the other attributes that I imply + */ + public UMLRTPortKind setWired(boolean wired) { + if (wired == isWired()) { + return this; + } else { + switch (this) { + case EXTERNAL_BEHAVIOR: + return SPP; + case SPP: + return EXTERNAL_BEHAVIOR; + case INTERNAL_BEHAVIOR: + return SAP; + case SAP: + return INTERNAL_BEHAVIOR; + default: + return NULL; + } + } + } + + /** + * Computes the kind that is like me but for ports of the given {@code publish} kind. + * + * @param publish + * the publication kind from which to derive a new port kind + * @return the new port kind, which may be {@link #NULL} if this value of {@code publish} + * does not make sense with the other attributes that I imply + */ + public UMLRTPortKind setPublish(boolean publish) { + if (publish == isPublish()) { + return this; + } else { + switch (this) { + case SPP: + return SAP; + case SAP: + return SPP; + default: + return NULL; + } + } + } + + /** + * Computes the kind of a port by its attributes. + * + * @param service + * whether the port is a service port + * @param behavior + * whether the port is a behavior port + * @param wired + * whether the port is wired + * @param publish + * whether the port is published + * + * @return the port kind, or {@link #NULL} if the specific attributes make no sense together + */ + public static UMLRTPortKind get(boolean service, boolean behavior, boolean wired, boolean publish) { + UMLRTPortKind result = NULL; + + if (service && wired && behavior && !publish) { + result = EXTERNAL_BEHAVIOR; + } else if (behavior && publish && !wired) { + result = SPP; // isService won't be checked here => Cf. bug 477033 + } else if (wired && behavior && !service && !publish) { + result = INTERNAL_BEHAVIOR; + } else if (service && wired && !behavior && !publish) { + result = RELAY; + } else if (behavior && !wired && !publish) { + result = SAP; // isService won't be checked here => Cf. bug 477033 + } + + return result; + } + + /** * Returns the literal value of the enumerator, which is its string representation. * <!-- begin-user-doc --> * <!-- end-user-doc -->
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTCapsuleImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTCapsuleImpl.java index 9146b16..aa0a85a 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTCapsuleImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTCapsuleImpl.java
@@ -20,10 +20,12 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.ECollections; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.Capsule; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.CapsulePart; @@ -107,15 +109,24 @@ ExtUMLExtPackage.Literals.STRUCTURED_CLASSIFIER__IMPLICIT_CONNECTOR, UMLPackage.Literals.CONNECTOR); - protected static class CapsuleAdapter<F extends UMLRTCapsuleImpl> extends Reactor<F> { + protected static class CapsuleAdapter<F extends UMLRTCapsuleImpl> extends ClassifierAdapter<F> { CapsuleAdapter(F facade) { super(facade); } @Override + protected void notifyGeneral(F owner, FacadeObject oldObject, FacadeObject newObject) { + // Notify the subset before the superset + if (owner.eNotificationRequired()) { + owner.eNotify(new ENotificationImpl(owner, Notification.SET, UMLRTUMLRTPackage.Literals.CAPSULE__SUPERCLASS, oldObject, newObject)); + } + super.notifyGeneral(owner, oldObject, newObject); + } + + @Override protected List<? extends FacadeObject> getFacadeList(EObject owner, EReference reference, EObject object) { - List<? extends FacadeObject> result = null; + List<? extends FacadeObject> result; if ((reference == UMLPackage.Literals.STRUCTURED_CLASSIFIER__OWNED_ATTRIBUTE) || (reference == ExtUMLExtPackage.Literals.STRUCTURED_CLASSIFIER__IMPLICIT_ATTRIBUTE)) { @@ -129,6 +140,8 @@ || (reference == ExtUMLExtPackage.Literals.ENCAPSULATED_CLASSIFIER__IMPLICIT_PORT)) { result = get().ports; + } else { + result = super.getFacadeList(owner, reference, object); } return result; @@ -153,7 +166,10 @@ || (reference == ExtUMLExtPackage.Literals.STRUCTURED_CLASSIFIER__IMPLICIT_CONNECTOR)) { result = get().connectors; } + } else { + result = super.validateObject(owner, reference, object); } + return result; } }
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTCapsulePartImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTCapsulePartImpl.java index 6ea2564..c4155f9 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTCapsulePartImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTCapsulePartImpl.java
@@ -21,12 +21,15 @@ import java.util.function.Predicate; import java.util.stream.Stream; +import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.CapsulePart; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.UMLRealTimePackage; +import org.eclipse.papyrusrt.umlrt.uml.FacadeObject; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsulePart; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsulePartKind; @@ -100,6 +103,81 @@ */ protected static final boolean OPTIONAL_EDEFAULT = false; + protected static class CapsulePartAdapter<F extends UMLRTCapsulePartImpl> extends ReplicationAdapter<F> { + CapsulePartAdapter(F facade) { + super(facade); + } + + @Override + protected void handleObjectReplaced(Notification msg, int position, FacadeObject oldObject, FacadeObject newObject) { + if (msg.getFeature() == UMLPackage.Literals.TYPED_ELEMENT__TYPE) { + if (get().eNotificationRequired()) { + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.CAPSULE_PART__TYPE, oldObject, newObject)); + } + } else { + super.handleObjectReplaced(msg, position, oldObject, newObject); + } + } + + @Override + protected void handleLowerBoundChanged(Object oldValue, Object newValue) { + super.handleLowerBoundChanged(oldValue, newValue); + + int oldInt = asIntegerBound(oldValue); + int newInt = asIntegerBound(newValue); + + if ((oldInt != newInt) && get().eNotificationRequired()) { + UMLRTCapsulePartImpl part = get(); + Property uml = part.toUML(); + + if (uml.getAggregation() == AggregationKind.COMPOSITE_LITERAL) { + part.eNotify(new ENotificationImpl(part, Notification.SET, UMLRTUMLRTPackage.Literals.CAPSULE_PART__OPTIONAL, + oldInt == 0, newInt == 0)); + } + + // Infer what the kind previously was + UMLRTCapsulePartKind kind = part.getKind(); + part.eNotify(new ENotificationImpl(part, Notification.SET, UMLRTUMLRTPackage.Literals.CAPSULE_PART__KIND, + UMLRTCapsulePartKind.get(oldInt, uml.getUpper(), uml.getAggregation()), kind)); + } + } + + @Override + protected void handleUpperBoundChanged(Object oldValue, Object newValue) { + super.handleUpperBoundChanged(oldValue, newValue); + + int oldInt = asIntegerBound(oldValue); + int newInt = asIntegerBound(newValue); + + if ((oldInt != newInt) && get().eNotificationRequired()) { + UMLRTCapsulePartImpl part = get(); + Property uml = part.toUML(); + + // Infer what the kind previously was + UMLRTCapsulePartKind kind = part.getKind(); + part.eNotify(new ENotificationImpl(part, Notification.SET, UMLRTUMLRTPackage.Literals.CAPSULE_PART__KIND, + UMLRTCapsulePartKind.get(uml.getLower(), oldInt, uml.getAggregation()), kind)); + } + } + + @Override + protected void handleValueReplaced(Notification msg, int position, Object oldValue, Object newValue) { + if (msg.getFeature() == UMLPackage.Literals.PROPERTY__AGGREGATION) { + if (get().eNotificationRequired()) { + UMLRTCapsulePartImpl part = get(); + Property uml = part.toUML(); + + // Infer what the kind previously was + UMLRTCapsulePartKind kind = part.getKind(); + part.eNotify(new ENotificationImpl(part, Notification.SET, UMLRTUMLRTPackage.Literals.CAPSULE_PART__KIND, + UMLRTCapsulePartKind.get(uml.getLower(), uml.getUpper(), (AggregationKind) oldValue), kind)); + } + } else { + super.handleValueReplaced(msg, position, oldValue, newValue); + } + } + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -133,6 +211,11 @@ return UMLRTUMLRTPackage.Literals.CAPSULE_PART; } + @Override + protected BasicFacadeAdapter<? extends UMLRTCapsulePartImpl> createFacadeAdapter() { + return new CapsulePartAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -171,20 +254,8 @@ */ @Override public UMLRTCapsulePartKind getKind() { - UMLRTCapsulePartKind result = UMLRTCapsulePartKind.NULL; Property uml = toUML(); - - if ((uml.getLower()) > 0 && (uml.getUpper() > 0)) { - result = UMLRTCapsulePartKind.FIXED; - } else if ((uml.getLower() == 0) || (uml.getUpper() == LiteralUnlimitedNatural.UNLIMITED)) { - if (uml.getAggregation() == AggregationKind.COMPOSITE_LITERAL) { - result = UMLRTCapsulePartKind.OPTIONAL; - } else if (uml.getAggregation() == AggregationKind.SHARED_LITERAL) { - result = UMLRTCapsulePartKind.PLUG_IN; - } - } - - return result; + return UMLRTCapsulePartKind.get(uml.getLower(), uml.getUpper(), uml.getAggregation()); } /**
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTClassifierImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTClassifierImpl.java index ee40016..48ef65f 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTClassifierImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTClassifierImpl.java
@@ -18,11 +18,18 @@ import java.util.Set; import java.util.stream.Stream; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.util.BasicEList.UnmodifiableEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.papyrusrt.umlrt.uml.FacadeObject; import org.eclipse.papyrusrt.umlrt.uml.UMLRTClassifier; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTFactory; import org.eclipse.papyrusrt.umlrt.uml.UMLRTPackage; import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; import org.eclipse.uml2.common.util.CacheAdapter; @@ -30,6 +37,7 @@ import org.eclipse.uml2.uml.Classifier; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Generalization; +import org.eclipse.uml2.uml.UMLPackage; /** * <!-- begin-user-doc --> @@ -46,6 +54,91 @@ * @generated */ public abstract class UMLRTClassifierImpl extends UMLRTNamedElementImpl implements UMLRTClassifier { + + protected static class ClassifierAdapter<F extends UMLRTClassifierImpl> extends NamedElementAdapter<F> { + + ClassifierAdapter(F facade) { + super(facade); + } + + @Override + public void setTarget(Notifier newTarget) { + super.setTarget(newTarget); + + if (newTarget instanceof Classifier) { + Classifier classifier = (Classifier) newTarget; + List<Generalization> generalizations = classifier.getGeneralizations(); + if (!generalizations.isEmpty()) { + // UML-RT supports single inheritance only + addAdapter(generalizations.get(0)); + } + } + } + + @Override + public void unsetTarget(Notifier oldTarget) { + if (oldTarget instanceof Classifier) { + Classifier classifier = (Classifier) oldTarget; + List<Generalization> generalizations = classifier.getGeneralizations(); + if (!generalizations.isEmpty()) { + generalizations.forEach(this::removeAdapter); + } + } + + super.unsetTarget(oldTarget); + } + + @Override + protected void handleObjectAdded(Notification msg, int position, EObject object) { + if (msg.getFeature() == UMLPackage.Literals.CLASSIFIER__GENERALIZATION) { + if (get().toUML().getGeneralizations().indexOf(object) == 0) { + // UML-RT only supports single generalization + addAdapter(object); + } + } else { + super.handleObjectAdded(msg, position, object); + } + } + + @Override + protected void handleObjectRemoved(Notification msg, int position, EObject object) { + if (msg.getFeature() == UMLPackage.Literals.CLASSIFIER__GENERALIZATION) { + removeAdapter(object); + } else { + super.handleObjectRemoved(msg, position, object); + } + } + + @Override + protected FacadeObject getFacade(EObject umlOwner, EReference umlReference, EObject object) { + if (object instanceof Generalization) { + Classifier general = ((Generalization) object).getGeneral(); + return (general == null) ? null : UMLRTFactory.create(general); + } else { + return super.getFacade(umlOwner, umlReference, object); + } + } + + @Override + protected void handleObjectReplaced(Notification msg, int position, FacadeObject oldObject, FacadeObject newObject) { + if (msg.getFeature() == UMLPackage.Literals.CLASSIFIER__GENERALIZATION) { + if (position == 0) { + notifyGeneral(get(), oldObject, newObject); + } + } else if (msg.getFeature() == UMLPackage.Literals.GENERALIZATION__GENERAL) { + notifyGeneral(get(), oldObject, newObject); + } else { + super.handleObjectReplaced(msg, position, oldObject, newObject); + } + } + + protected void notifyGeneral(F owner, FacadeObject oldObject, FacadeObject newObject) { + if (owner.eNotificationRequired()) { + owner.eNotify(new ENotificationImpl(owner, Notification.SET, UMLRTUMLRTPackage.Literals.CLASSIFIER__GENERAL, oldObject, newObject)); + } + } + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -67,6 +160,11 @@ return UMLRTUMLRTPackage.Literals.CLASSIFIER; } + @Override + protected BasicFacadeAdapter<? extends UMLRTClassifierImpl> createFacadeAdapter() { + return new ClassifierAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc -->
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTConnectorImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTConnectorImpl.java index a532ad8..80634eb 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTConnectorImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTConnectorImpl.java
@@ -12,10 +12,19 @@ */ package org.eclipse.papyrusrt.umlrt.uml.internal.facade.impl; +import static org.eclipse.papyrusrt.umlrt.uml.internal.facade.impl.UMLRTReplicatedElementImpl.ReplicationAdapter.asIntegerBound; +import static org.eclipse.papyrusrt.umlrt.uml.internal.facade.impl.UMLRTReplicatedElementImpl.ReplicationAdapter.valueOf; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTConnector; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.UMLRealTimePackage; +import org.eclipse.papyrusrt.umlrt.uml.FacadeObject; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsulePart; import org.eclipse.papyrusrt.umlrt.uml.UMLRTConnector; @@ -25,8 +34,11 @@ import org.eclipse.papyrusrt.umlrt.uml.internal.impl.InternalUMLRTElement; import org.eclipse.uml2.uml.Connector; import org.eclipse.uml2.uml.ConnectorEnd; +import org.eclipse.uml2.uml.MultiplicityElement; +import org.eclipse.uml2.uml.OpaqueExpression; import org.eclipse.uml2.uml.Port; import org.eclipse.uml2.uml.UMLPackage; +import org.eclipse.uml2.uml.ValueSpecification; /** * <!-- begin-user-doc --> @@ -80,6 +92,161 @@ connector -> (UMLRTConnectorImpl) connector.getRedefinedConnector(), UMLRTConnectorImpl::new); + protected static class ConnectorAdapter<F extends UMLRTConnectorImpl> extends NamedElementAdapter<F> { + ConnectorAdapter(F facade) { + super(facade); + } + + @Override + public void setTarget(Notifier newTarget) { + super.setTarget(newTarget); + + if (newTarget instanceof Connector) { + ((Connector) newTarget).getEnds().forEach(this::addAdapter); + } else if (newTarget instanceof MultiplicityElement) { + MultiplicityElement mult = (MultiplicityElement) newTarget; + if (mult.getUpperValue() != null) { + addAdapter(mult.getUpperValue()); + } + } + } + + @Override + public void unsetTarget(Notifier oldTarget) { + if (oldTarget instanceof Connector) { + ((Connector) oldTarget).getEnds().forEach(this::removeAdapter); + } else if (oldTarget instanceof MultiplicityElement) { + MultiplicityElement mult = (MultiplicityElement) oldTarget; + if (mult.getUpperValue() != null) { + removeAdapter(mult.getUpperValue()); + } + } + + super.setTarget(oldTarget); + } + + @Override + protected void handleObjectAdded(Notification msg, int position, EObject object) { + if (msg.getFeature() == UMLPackage.Literals.CONNECTOR__END) { + addAdapter(object); + } + + super.handleObjectAdded(msg, position, object); + } + + @Override + protected void handleObjectRemoved(Notification msg, int position, EObject object) { + super.handleObjectRemoved(msg, position, object); + + if (msg.getFeature() == UMLPackage.Literals.CONNECTOR__END) { + removeAdapter(object); + } + } + + @Override + protected void handleObjectReplaced(Notification msg, int position, EObject oldObject, EObject newObject) { + if (msg.getFeature() == UMLPackage.Literals.CONNECTOR__END) { + removeAdapter(oldObject); + addAdapter(newObject); + } else if (msg.getFeature() == UMLPackage.Literals.MULTIPLICITY_ELEMENT__UPPER_VALUE) { + if (oldObject != null) { + removeAdapter(oldObject); + } + if (newObject != null) { + addAdapter(newObject); + } + + boolean isSource = msg.getNotifier() == get().umlEnd(0); + handleUpperBoundChanged(isSource, asIntegerBound(valueOf((ValueSpecification) oldObject)), + asIntegerBound(valueOf((ValueSpecification) newObject))); + } else { + super.handleObjectReplaced(msg, position, oldObject, newObject); + } + } + + @Override + protected void handleObjectReplaced(Notification msg, int position, FacadeObject oldObject, FacadeObject newObject) { + if (msg.getFeature() == UMLPackage.Literals.CONNECTOR_END__ROLE) { + if (get().eNotificationRequired()) { + boolean isSource = msg.getNotifier() == get().umlEnd(0); + EStructuralFeature feature = isSource + ? UMLRTUMLRTPackage.Literals.CONNECTOR__SOURCE + : UMLRTUMLRTPackage.Literals.CONNECTOR__TARGET; + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), feature, oldObject, newObject)); + } + } else if (msg.getFeature() == UMLPackage.Literals.CONNECTOR_END__PART_WITH_PORT) { + if (get().eNotificationRequired()) { + boolean isSource = msg.getNotifier() == get().umlEnd(0); + EStructuralFeature feature = isSource + ? UMLRTUMLRTPackage.Literals.CONNECTOR__SOURCE_PART_WITH_PORT + : UMLRTUMLRTPackage.Literals.CONNECTOR__TARGET_PART_WITH_PORT; + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), feature, oldObject, newObject)); + } + } else { + super.handleObjectReplaced(msg, position, oldObject, newObject); + } + } + + @Override + protected void handleValueReplaced(Notification msg, int position, Object oldValue, Object newValue) { + if ((msg.getFeature() == UMLPackage.Literals.LITERAL_INTEGER__VALUE) + || (msg.getFeature() == UMLPackage.Literals.LITERAL_UNLIMITED_NATURAL__VALUE) + || (msg.getFeature() == UMLPackage.Literals.LITERAL_STRING__VALUE) + || ((msg.getFeature() == UMLPackage.Literals.OPAQUE_EXPRESSION__BODY) + && (position == 0))) { + + ValueSpecification bound = (ValueSpecification) msg.getNotifier(); + MultiplicityElement mult = (MultiplicityElement) bound.getOwner(); + boolean isSource = mult == get().umlEnd(0); + + handleUpperBoundChanged(isSource, asIntegerBound(oldValue), asIntegerBound(newValue)); + } else { + super.handleValueReplaced(msg, position, oldValue, newValue); + } + } + + @Override + protected void handleValueAdded(Notification msg, int position, Object value) { + if ((msg.getFeature() == UMLPackage.Literals.OPAQUE_EXPRESSION__BODY) + && (position == 0)) { + + ValueSpecification bound = (ValueSpecification) msg.getNotifier(); + MultiplicityElement mult = (MultiplicityElement) bound.getOwner(); + boolean isSource = mult == get().umlEnd(0); + + handleUpperBoundChanged(isSource, 1, asIntegerBound(value)); + } else { + super.handleValueAdded(msg, position, value); + } + } + + @Override + protected void handleValueRemoved(Notification msg, int position, Object value) { + if ((msg.getFeature() == UMLPackage.Literals.OPAQUE_EXPRESSION__BODY) + && ((OpaqueExpression) msg.getNotifier()).getBodies().isEmpty()) { + + ValueSpecification bound = (ValueSpecification) msg.getNotifier(); + MultiplicityElement mult = (MultiplicityElement) bound.getOwner(); + boolean isSource = mult == get().umlEnd(0); + + handleUpperBoundChanged(isSource, asIntegerBound(value), mult.getUpper()); + } else { + super.handleValueRemoved(msg, position, value); + } + } + + protected void handleUpperBoundChanged(boolean isSource, int oldValue, int newValue) { + if (get().eNotificationRequired()) { + EStructuralFeature feature = isSource + ? UMLRTUMLRTPackage.Literals.CONNECTOR__SOURCE_REPLICATION_FACTOR + : UMLRTUMLRTPackage.Literals.CONNECTOR__TARGET_REPLICATION_FACTOR; + + get().eNotify(new ENotificationImpl(get(), Notification.SET, feature, + oldValue, newValue)); + } + } + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -113,6 +280,11 @@ return UMLRTUMLRTPackage.Literals.CONNECTOR; } + @Override + protected BasicFacadeAdapter<? extends UMLRTConnectorImpl> createFacadeAdapter() { + return new ConnectorAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc -->
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTNamedElementImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTNamedElementImpl.java index c74977f..9c1caba 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTNamedElementImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTNamedElementImpl.java
@@ -20,9 +20,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.ECollections; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.papyrusrt.umlrt.uml.UMLRTFactory; @@ -37,6 +39,7 @@ import org.eclipse.uml2.common.util.UML2Util; import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.Namespace; +import org.eclipse.uml2.uml.UMLPackage; /** * <!-- begin-user-doc --> @@ -151,6 +154,25 @@ */ protected static final boolean IS_EXCLUDED_EDEFAULT = false; + + protected static class NamedElementAdapter<F extends UMLRTNamedElementImpl> extends Reactor<F> { + + NamedElementAdapter(F facade) { + super(facade); + } + + @Override + protected void handleValueReplaced(Notification msg, int position, Object oldValue, Object newValue) { + if (msg.getFeature() == UMLPackage.Literals.NAMED_ELEMENT__NAME) { + if (get().eNotificationRequired()) { + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.NAMED_ELEMENT__NAME, oldValue, newValue)); + } + } else { + super.handleValueReplaced(msg, position, oldValue, newValue); + } + } + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -172,6 +194,11 @@ return UMLRTUMLRTPackage.Literals.NAMED_ELEMENT; } + @Override + protected BasicFacadeAdapter<? extends UMLRTNamedElementImpl> createFacadeAdapter() { + return new NamedElementAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc -->
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTPackageImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTPackageImpl.java index 46c0215..9ffcc13 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTPackageImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTPackageImpl.java
@@ -20,17 +20,25 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.Notifier; +import org.eclipse.emf.common.notify.impl.AdapterImpl; +import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.Capsule; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.ProtocolContainer; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.UMLRealTimePackage; +import org.eclipse.papyrusrt.umlrt.uml.FacadeObject; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; import org.eclipse.papyrusrt.umlrt.uml.UMLRTPackage; import org.eclipse.papyrusrt.umlrt.uml.UMLRTProtocol; import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; import org.eclipse.uml2.uml.Class; import org.eclipse.uml2.uml.Collaboration; +import org.eclipse.uml2.uml.NamedElement; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.Profile; import org.eclipse.uml2.uml.UMLPackage; @@ -79,6 +87,118 @@ null, UMLPackage.Literals.PACKAGE); + protected static class PackageAdapter<F extends UMLRTPackageImpl> extends NamedElementAdapter<F> { + + // Cannot attach ourselves to protocol-containers because otherwise they + // will be mistaken for our own package façade via getFacadeAdapter(...) + private final Nested protocolContainerAdapter = new Nested(); + + PackageAdapter(F facade) { + super(facade); + } + + @Override + public void setTarget(Notifier newTarget) { + super.setTarget(newTarget); + + if ((newTarget instanceof Package) && !isProtocolContainer((Package) newTarget)) { + // Look for protocol-containers + ((Package) newTarget).getNestedPackages().stream() + .filter(UMLRTPackageImpl::isProtocolContainer) + .forEach(protocolContainerAdapter::addAdapter); + } + } + + @Override + public void unsetTarget(Notifier oldTarget) { + if (oldTarget instanceof Package) { + ((Package) oldTarget).getNestedPackages().forEach(protocolContainerAdapter::removeAdapter); + } + + super.unsetTarget(oldTarget); + } + + @Override + protected List<? extends FacadeObject> getFacadeList(EObject owner, EReference reference, EObject object) { + List<? extends FacadeObject> result; + + if (reference == UMLPackage.Literals.PACKAGE__PACKAGED_ELEMENT) { + result = (object instanceof Package) + ? get().nestedPackages + : (object instanceof Class) + ? get().capsules + : (object instanceof Collaboration) + ? get().protocols + : null; + } else { + result = super.getFacadeList(owner, reference, object); + } + + return result; + } + + @Override + protected InternalFacadeEList<? extends FacadeObject> validateObject(EObject owner, EReference reference, FacadeObject object) { + InternalFacadeEList<? extends FacadeObject> result = null; + + if (object instanceof UMLRTPackage) { + if (reference == UMLPackage.Literals.PACKAGE__PACKAGED_ELEMENT) { + result = get().nestedPackages; + } + } else if (object instanceof UMLRTCapsule) { + if (reference == UMLPackage.Literals.PACKAGE__PACKAGED_ELEMENT) { + result = get().capsules; + } + } else if (object instanceof UMLRTProtocol) { + if (reference == UMLPackage.Literals.PACKAGE__PACKAGED_ELEMENT) { + result = get().protocols; + } + } else { + result = super.validateObject(owner, reference, object); + } + + return result; + } + + @Override + public void tickle(NamedElement element) { + if (element instanceof Package) { + if (isProtocolContainer((org.eclipse.uml2.uml.Package) element)) { + addAdapter(element); + } + } else { + super.tickle(element); + } + } + + // + // Nested types + // + + private final class Nested extends AdapterImpl { + void addAdapter(Notifier notifier) { + EList<Adapter> adapters = notifier.eAdapters(); + if (!adapters.contains(this)) { + adapters.add(this); + } + } + + void removeAdapter(Notifier notifier) { + notifier.eAdapters().remove(this); + } + + @Override + public void notifyChanged(Notification msg) { + // Forward to the real package adapter + PackageAdapter.this.notifyChanged(msg); + } + } + } + + InternalFacadeEList<UMLRTPackage> nestedPackages; + InternalFacadeEList<UMLRTCapsule> capsules; + InternalFacadeEList<UMLRTProtocol> protocols; + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -138,6 +258,11 @@ return UMLRTUMLRTPackage.Literals.PACKAGE; } + @Override + protected BasicFacadeAdapter<? extends UMLRTPackageImpl> createFacadeAdapter() { + return new PackageAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -146,7 +271,10 @@ */ @Override public List<UMLRTPackage> getNestedPackages() { - return getFacades(NESTED_PACKAGE_REFERENCE); + if (nestedPackages == null) { + nestedPackages = (InternalFacadeEList<UMLRTPackage>) getFacades(NESTED_PACKAGE_REFERENCE); + } + return nestedPackages; } /** @@ -197,7 +325,10 @@ */ @Override public List<UMLRTCapsule> getCapsules() { - return getFacades(CAPSULE_REFERENCE); + if (capsules == null) { + capsules = (InternalFacadeEList<UMLRTCapsule>) getFacades(CAPSULE_REFERENCE); + } + return capsules; } /** @@ -236,12 +367,16 @@ */ @Override public List<UMLRTProtocol> getProtocols() { - return toUML().getNestedPackages().stream() - .filter(UMLRTPackageImpl::isProtocolContainer) - .map(UMLRTPackageImpl::getProtocol) - .map(UMLRTProtocol::getInstance) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + if (protocols == null) { + List<UMLRTProtocol> protocols_ = toUML().getNestedPackages().stream() + .filter(UMLRTPackageImpl::isProtocolContainer) + .map(UMLRTPackageImpl::getProtocol) + .map(UMLRTProtocol::getInstance) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + protocols = new FacadeObjectEList<>(this, UMLRTProtocol.class, UMLRTUMLRTPackage.PACKAGE__PROTOCOL, protocols_); + } + return protocols; } /**
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTPortImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTPortImpl.java index 2ac4a49..d38bdd7 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTPortImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTPortImpl.java
@@ -22,12 +22,18 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.PortRegistrationType; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTPort; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.UMLRealTimePackage; +import org.eclipse.papyrusrt.umlrt.uml.FacadeObject; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsulePart; import org.eclipse.papyrusrt.umlrt.uml.UMLRTConnector; @@ -48,6 +54,7 @@ import org.eclipse.uml2.uml.Type; import org.eclipse.uml2.uml.UMLPackage; import org.eclipse.uml2.uml.VisibilityKind; +import org.eclipse.uml2.uml.util.UMLUtil; /** * <!-- begin-user-doc --> @@ -223,6 +230,133 @@ */ protected static final boolean IS_CONNECTED_OUTSIDE_EDEFAULT = false; + protected static class PortAdapter<F extends UMLRTPortImpl> extends ReplicationAdapter<F> { + PortAdapter(F facade) { + super(facade); + } + + @Override + public void setTarget(Notifier newTarget) { + super.setTarget(newTarget); + + if (newTarget instanceof Port) { + RTPort stereotype = UMLUtil.getStereotypeApplication((Port) newTarget, RTPort.class); + if (stereotype != null) { + addAdapter(stereotype); + } + } + } + + @Override + public void unsetTarget(Notifier newTarget) { + if (newTarget instanceof Port) { + RTPort stereotype = UMLUtil.getStereotypeApplication((Port) newTarget, RTPort.class); + if (stereotype != null) { + removeAdapter(stereotype); + } + } + + super.setTarget(newTarget); + } + + @Override + protected FacadeObject getFacade(EObject owner, EReference reference, EObject object) { + FacadeObject result = super.getFacade(owner, reference, object); + + if ((result instanceof UMLRTProtocol) && get().isConjugated()) { + result = ((UMLRTProtocol) result).getConjugate(); + } + + return result; + } + + @Override + protected void handleObjectReplaced(Notification msg, int position, FacadeObject oldObject, FacadeObject newObject) { + if (msg.getFeature() == UMLPackage.Literals.TYPED_ELEMENT__TYPE) { + if (get().eNotificationRequired()) { + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__TYPE, oldObject, newObject)); + } + } else { + super.handleObjectReplaced(msg, position, oldObject, newObject); + } + } + + @Override + protected void handleValueReplaced(Notification msg, int position, Object oldValue, Object newValue) { + if (msg.getFeature() == UMLPackage.Literals.PORT__IS_CONJUGATED) { + if (get().eNotificationRequired()) { + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__CONJUGATED, oldValue, newValue)); + UMLRTProtocol type = get().getType(); + + if (type != null) { + // It is now the conjugate of what it was + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__TYPE, + type.getConjugate(), type)); + } + } + } else if (msg.getFeature() == UMLPackage.Literals.PORT__IS_SERVICE) { + if (get().eNotificationRequired()) { + UMLRTPortImpl port = get(); + port.eNotify(new ENotificationImpl(port, msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__SERVICE, oldValue, newValue)); + + // Infer what the kind previously was + UMLRTPortKind kind = port.getKind(); + port.eNotify(new ENotificationImpl(port, msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__KIND, + UMLRTPortKind.get((boolean) oldValue, port.isBehavior(), port.isWired(), port.isPublish()), + kind)); + } + } else if (msg.getFeature() == UMLPackage.Literals.PORT__IS_BEHAVIOR) { + if (get().eNotificationRequired()) { + UMLRTPortImpl port = get(); + port.eNotify(new ENotificationImpl(port, msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__BEHAVIOR, oldValue, newValue)); + + // Infer what the kind previously was + UMLRTPortKind kind = port.getKind(); + port.eNotify(new ENotificationImpl(port, msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__KIND, + UMLRTPortKind.get(port.isService(), (boolean) oldValue, port.isWired(), port.isPublish()), + kind)); + } + } else if (msg.getFeature() == UMLRealTimePackage.Literals.RT_PORT__IS_WIRED) { + if (get().eNotificationRequired()) { + UMLRTPortImpl port = get(); + port.eNotify(new ENotificationImpl(port, msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__WIRED, oldValue, newValue)); + + // Infer what the kind previously was + UMLRTPortKind kind = port.getKind(); + port.eNotify(new ENotificationImpl(port, msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__KIND, + UMLRTPortKind.get(port.isService(), port.isBehavior(), (boolean) oldValue, port.isPublish()), + kind)); + } + } else if (msg.getFeature() == UMLRealTimePackage.Literals.RT_PORT__IS_PUBLISH) { + if (get().eNotificationRequired()) { + UMLRTPortImpl port = get(); + port.eNotify(new ENotificationImpl(port, msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__PUBLISH, oldValue, newValue)); + + // Infer what the kind previously was + UMLRTPortKind kind = port.getKind(); + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__KIND, + UMLRTPortKind.get(port.isService(), port.isBehavior(), port.isWired(), (boolean) oldValue), + kind)); + } + } else if (msg.getFeature() == UMLRealTimePackage.Literals.RT_PORT__IS_NOTIFICATION) { + if (get().eNotificationRequired()) { + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__NOTIFICATION, oldValue, newValue)); + } + } else if (msg.getFeature() == UMLRealTimePackage.Literals.RT_PORT__REGISTRATION) { + if (get().eNotificationRequired()) { + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__REGISTRATION, oldValue, newValue)); + } + } else if (msg.getFeature() == UMLRealTimePackage.Literals.RT_PORT__REGISTRATION_OVERRIDE) { + if (get().eNotificationRequired()) { + get().eNotify(new ENotificationImpl(get(), msg.getEventType(), UMLRTUMLRTPackage.Literals.PORT__REGISTRATION_OVERRIDE, oldValue, newValue)); + } + } else { + super.handleValueReplaced(msg, position, oldValue, newValue); + } + } + + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -256,6 +390,11 @@ return UMLRTUMLRTPackage.Literals.PORT; } + @Override + protected BasicFacadeAdapter<? extends UMLRTPortImpl> createFacadeAdapter() { + return new PortAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -379,21 +518,7 @@ */ @Override public UMLRTPortKind getKind() { - UMLRTPortKind result = UMLRTPortKind.NULL; - - if (isService() && isWired() && isBehavior() && !isPublish()) { - result = UMLRTPortKind.EXTERNAL_BEHAVIOR; - } else if (isBehavior() && isPublish() && !isWired()) { - result = UMLRTPortKind.SPP; // isService won't be checked here => Cf. bug 477033 - } else if (isWired() && isBehavior() && !isService() && !isPublish()) { - result = UMLRTPortKind.INTERNAL_BEHAVIOR; - } else if (isService() && isWired() && !isBehavior() && !isPublish()) { - result = UMLRTPortKind.RELAY; - } else if (isBehavior() && !isWired() && !isPublish()) { - result = UMLRTPortKind.SAP;// isService won't be checked here => Cf. bug 477033 - } - - return result; + return UMLRTPortKind.get(isService(), isBehavior(), isWired(), isPublish()); } /**
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolImpl.java index f3c43b9..ac30989 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolImpl.java
@@ -32,6 +32,7 @@ import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.Protocol; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTMessageKind; @@ -117,6 +118,7 @@ private final Supplier<UMLRTProtocol> conjugate; static { + EnumMap<RTMessageKind, Integer> references = new EnumMap<>(RTMessageKind.class); references.put(RTMessageKind.IN, UMLRTUMLRTPackage.PROTOCOL__IN_MESSAGE); references.put(RTMessageKind.IN_OUT, UMLRTUMLRTPackage.PROTOCOL__IN_OUT_MESSAGE); @@ -134,7 +136,7 @@ protocol -> requireMessageSet((Collaboration) protocol, kind)))); } - protected static class ProtocolAdapter<F extends UMLRTProtocolImpl> extends Reactor<F> { + protected static class ProtocolAdapter<F extends UMLRTProtocolImpl> extends ClassifierAdapter<F> { ProtocolAdapter(F facade) { super(facade); @@ -185,14 +187,25 @@ if ((result instanceof UMLRTProtocolMessage) && get().isConjugate()) { result = ((UMLRTProtocolMessage) result).getConjugate(); + } else if ((result instanceof UMLRTProtocol) && get().isConjugate()) { + result = ((UMLRTProtocol) result).getConjugate(); } return result; } @Override + protected void notifyGeneral(F owner, FacadeObject oldObject, FacadeObject newObject) { + // Notify the subset before the superset + if (owner.eNotificationRequired()) { + owner.eNotify(new ENotificationImpl(owner, Notification.SET, UMLRTUMLRTPackage.Literals.PROTOCOL__SUPER_PROTOCOL, oldObject, newObject)); + } + super.notifyGeneral(owner, oldObject, newObject); + } + + @Override protected List<? extends FacadeObject> getFacadeList(EObject owner, EReference reference, EObject object) { - List<? extends FacadeObject> result = null; + List<? extends FacadeObject> result; if ((reference == UMLPackage.Literals.INTERFACE__OWNED_OPERATION) || (reference == ExtUMLExtPackage.Literals.INTERFACE__IMPLICIT_OPERATION)) { @@ -210,8 +223,15 @@ case IN_OUT: result = get().inOutMessages; break; + default: + result = null; + break; } + } else { + result = null; } + } else { + result = super.getFacadeList(owner, reference, object); } return result; @@ -229,6 +249,15 @@ } @Override + protected void handleObjectAdded(Notification msg, int position, FacadeObject object) { + super.handleObjectAdded(msg, position, object); + + if (object instanceof UMLRTProtocolMessageImpl) { + ((UMLRTProtocolMessageImpl) object).kindChanged(); + } + } + + @Override protected void handleObjectRemoved(Notification msg, int position, EObject object) { if (msg.getFeature() == UMLPackage.Literals.PACKAGE__PACKAGED_ELEMENT) { if (object instanceof Interface) { @@ -265,6 +294,8 @@ break; } } + } else { + result = super.validateObject(owner, reference, object); } return result;
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolMessageImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolMessageImpl.java index 0051f4e..4547937 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolMessageImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTProtocolMessageImpl.java
@@ -20,8 +20,11 @@ import java.util.Optional; import java.util.function.Supplier; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.NotificationWrapper; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTMessageKind; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTMessageSet; import org.eclipse.papyrusrt.umlrt.uml.UMLRTNamedElement; @@ -32,6 +35,7 @@ import org.eclipse.papyrusrt.umlrt.uml.internal.util.CachedReference; import org.eclipse.uml2.uml.CallEvent; import org.eclipse.uml2.uml.Collaboration; +import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Interface; import org.eclipse.uml2.uml.Operation; import org.eclipse.uml2.uml.Package; @@ -90,8 +94,40 @@ */ protected static final boolean IS_CONJUGATE_EDEFAULT = false; + protected static class MessageAdapter<F extends UMLRTProtocolMessageImpl> extends NamedElementAdapter<F> { + MessageAdapter(F facade) { + super(facade); + } + + @Override + protected void handleReference(Notification msg) { + if (msg.getFeature() == UMLPackage.Literals.BEHAVIORAL_FEATURE__OWNED_PARAMETER) { + if (get().eNotificationRequired()) { + UMLRTProtocolMessageImpl message = get(); + + // We don't have façades for parameters + message.eNotify(new NotificationWrapper(msg) { + @Override + public Object getNotifier() { + return message; + } + + @Override + public Object getFeature() { + return UMLRTUMLRTPackage.Literals.PROTOCOL_MESSAGE__PARAMETER; + } + + }); + } + } else { + super.handleReference(msg); + } + } + } + private final boolean isConjugate; private final Supplier<UMLRTProtocolMessage> conjugate; + private RTMessageKind kind; /** * <!-- begin-user-doc --> @@ -114,6 +150,16 @@ init(base.toUML(), base.toRT()); } + @Override + <F extends FacadeObjectImpl> F init(Element element, EObject stereotype) { + F result = super.init(element, stereotype); + + // Initialize my kind + getKind(); + + return result; + } + /** * Obtains the protocol message façade for the message represented by the given * UML operation. @@ -157,6 +203,11 @@ return UMLRTUMLRTPackage.Literals.PROTOCOL_MESSAGE; } + @Override + protected BasicFacadeAdapter<? extends UMLRTProtocolMessageImpl> createFacadeAdapter() { + return new MessageAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -195,7 +246,21 @@ */ @Override public RTMessageKind getKind() { - return forConjugation(getMessageSet().map(RTMessageSet::getRtMsgKind).orElse(null)); + if (kind == null) { + kind = forConjugation(getMessageSet().map(RTMessageSet::getRtMsgKind).orElse(null)); + } + + return kind; + } + + void kindChanged() { + RTMessageKind oldKind = kind; + kind = null; + RTMessageKind newKind = getKind(); + + if ((oldKind != newKind) && eNotificationRequired()) { + eNotify(new ENotificationImpl(this, Notification.SET, UMLRTUMLRTPackage.Literals.PROTOCOL_MESSAGE__KIND, oldKind, newKind)); + } } Optional<RTMessageSet> getMessageSet() {
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTReplicatedElementImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTReplicatedElementImpl.java index d571717..3044719 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTReplicatedElementImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src-facade/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/UMLRTReplicatedElementImpl.java
@@ -14,18 +14,24 @@ import java.util.Objects; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; import org.eclipse.papyrusrt.umlrt.uml.UMLRTReplicatedElement; import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; import org.eclipse.uml2.uml.LiteralInteger; +import org.eclipse.uml2.uml.LiteralString; import org.eclipse.uml2.uml.LiteralUnlimitedNatural; import org.eclipse.uml2.uml.MultiplicityElement; import org.eclipse.uml2.uml.OpaqueExpression; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.UMLPackage; import org.eclipse.uml2.uml.ValueSpecification; +import org.eclipse.uml2.uml.util.UMLSwitch; /** * <!-- begin-user-doc --> @@ -74,6 +80,196 @@ */ protected static final boolean SYMBOLIC_REPLICATION_FACTOR_EDEFAULT = false; + protected static class ReplicationAdapter<F extends UMLRTReplicatedElementImpl> extends NamedElementAdapter<F> { + ReplicationAdapter(F facade) { + super(facade); + } + + @Override + public void setTarget(Notifier newTarget) { + super.setTarget(newTarget); + + if (newTarget instanceof MultiplicityElement) { + MultiplicityElement mult = (MultiplicityElement) newTarget; + if (mult.getLowerValue() != null) { + addAdapter(mult.getLowerValue()); + } + if (mult.getUpperValue() != null) { + addAdapter(mult.getUpperValue()); + } + } + } + + @Override + public void unsetTarget(Notifier oldTarget) { + if (oldTarget instanceof MultiplicityElement) { + MultiplicityElement mult = (MultiplicityElement) oldTarget; + if (mult.getLowerValue() != null) { + removeAdapter(mult.getLowerValue()); + } + if (mult.getUpperValue() != null) { + removeAdapter(mult.getUpperValue()); + } + } + + super.setTarget(oldTarget); + } + + @Override + protected void handleObjectReplaced(Notification msg, int position, EObject oldObject, EObject newObject) { + if (msg.getFeature() == UMLPackage.Literals.MULTIPLICITY_ELEMENT__LOWER_VALUE) { + if (oldObject != null) { + removeAdapter(oldObject); + } + if (newObject != null) { + addAdapter(newObject); + } + handleLowerBoundChanged(valueOf((ValueSpecification) oldObject), valueOf((ValueSpecification) newObject)); + } else if (msg.getFeature() == UMLPackage.Literals.MULTIPLICITY_ELEMENT__UPPER_VALUE) { + if (oldObject != null) { + removeAdapter(oldObject); + } + if (newObject != null) { + addAdapter(newObject); + } + handleUpperBoundChanged(valueOf((ValueSpecification) oldObject), valueOf((ValueSpecification) newObject)); + } else { + super.handleObjectReplaced(msg, position, oldObject, newObject); + } + } + + protected static Object valueOf(ValueSpecification valueSpecification) { + return (valueSpecification == null) + ? 1 // The default derivation of the bound when there is no value specified + : new UMLSwitch<Object>() { + @Override + public Object caseLiteralInteger(LiteralInteger object) { + return object.getValue(); + } + + @Override + public Object caseLiteralUnlimitedNatural(LiteralUnlimitedNatural object) { + return object.getValue(); + } + + @Override + public Object caseLiteralString(LiteralString object) { + return object.getValue(); + } + + @Override + public Object caseOpaqueExpression(OpaqueExpression object) { + return object.getBodies().isEmpty() ? null : object.getBodies().get(0); + } + + @Override + public Object caseValueSpecification(ValueSpecification object) { + return object.stringValue(); + } + }.doSwitch(valueSpecification); + } + + protected static int asIntegerBound(Object bound) { + int result = 1; + + if (bound instanceof Integer) { + result = (Integer) bound; + } else if (bound instanceof String) { + try { + result = Integer.parseInt((String) bound); + } catch (Exception e) { + // Pass + } + } + + return result; + } + + @Override + protected void handleValueReplaced(Notification msg, int position, Object oldValue, Object newValue) { + if ((msg.getFeature() == UMLPackage.Literals.LITERAL_INTEGER__VALUE) + || (msg.getFeature() == UMLPackage.Literals.LITERAL_UNLIMITED_NATURAL__VALUE) + || (msg.getFeature() == UMLPackage.Literals.LITERAL_STRING__VALUE) + || ((msg.getFeature() == UMLPackage.Literals.OPAQUE_EXPRESSION__BODY) + && (position == 0))) { + + MultiplicityElement mult = get().toUML(); + ValueSpecification bound = (ValueSpecification) msg.getNotifier(); + + if (bound == mult.getLowerValue()) { + handleLowerBoundChanged(oldValue, newValue); + } else { + handleUpperBoundChanged(oldValue, newValue); + } + } else { + super.handleValueReplaced(msg, position, oldValue, newValue); + } + } + + @Override + protected void handleValueAdded(Notification msg, int position, Object value) { + if ((msg.getFeature() == UMLPackage.Literals.OPAQUE_EXPRESSION__BODY) + && (position == 0)) { + + MultiplicityElement mult = get().toUML(); + ValueSpecification bound = (ValueSpecification) msg.getNotifier(); + + if (bound == mult.getLowerValue()) { + handleLowerBoundChanged(null, value); + } else { + handleUpperBoundChanged(null, value); + } + } else { + super.handleValueAdded(msg, position, value); + } + } + + @Override + protected void handleValueRemoved(Notification msg, int position, Object value) { + if ((msg.getFeature() == UMLPackage.Literals.OPAQUE_EXPRESSION__BODY) + && ((OpaqueExpression) msg.getNotifier()).getBodies().isEmpty()) { + + MultiplicityElement mult = get().toUML(); + ValueSpecification bound = (ValueSpecification) msg.getNotifier(); + + if (bound == mult.getLowerValue()) { + handleLowerBoundChanged(value, null); + } else { + handleUpperBoundChanged(value, null); + } + } else { + super.handleValueRemoved(msg, position, value); + } + } + + protected void handleLowerBoundChanged(Object oldValue, Object newValue) { + // We don't do lower bounds at this level of abstraction + } + + protected void handleUpperBoundChanged(Object oldValue, Object newValue) { + if (get().eNotificationRequired()) { + if (newValue instanceof Integer) { + Integer oldInt = (oldValue instanceof Integer) ? (Integer) oldValue : 1; + get().eNotify(new ENotificationImpl(get(), Notification.SET, + UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR, + oldInt, newValue)); + + String oldString = (oldValue instanceof String) ? (String) oldValue : oldInt.toString(); + get().eNotify(new ENotificationImpl(get(), Notification.SET, + UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, + oldString, String.valueOf(newValue))); + } else { + // Not numeric. Go for the strings. But not "null" + String oldString = (oldValue == null) ? null : oldValue.toString(); + String newString = (newValue == null) ? null : newValue.toString(); + get().eNotify(new ENotificationImpl(get(), Notification.SET, + UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, + oldString, newString)); + } + } + } + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -95,6 +291,11 @@ return UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT; } + @Override + protected BasicFacadeAdapter<? extends UMLRTReplicatedElementImpl> createFacadeAdapter() { + return new ReplicationAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc -->
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/FacadeObjectImpl.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/FacadeObjectImpl.java index c3c9179..190d0df 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/FacadeObjectImpl.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src/org/eclipse/papyrusrt/umlrt/uml/internal/facade/impl/FacadeObjectImpl.java
@@ -57,7 +57,7 @@ try { referenceKind = ReferenceKind.valueOf(config); if (referenceKind != FACADE_REFERENCE_KIND_DEFAULT) { - UMLRTUMLPlugin.INSTANCE.log(String.format("Using %s reference for facade.", referenceKind)); + UMLRTUMLPlugin.INSTANCE.log(String.format("Using %s references for facade.", referenceKind)); } } catch (Exception e) { UMLRTUMLPlugin.INSTANCE.log("Unrecognized value of papyrusrt.facadeReferenceKind system property: " + config); @@ -209,7 +209,7 @@ removeAdapter(getTarget()); } - return facade.get(); + return result; } @Override @@ -345,13 +345,13 @@ } protected FacadeObject getFacade(Notification msg, EObject object) { - return getFacade((EObject) msg.getNotifier(), (EReference) msg.getFeature(), object); + return (object == null) ? null : getFacade((EObject) msg.getNotifier(), (EReference) msg.getFeature(), object); } protected FacadeObject getFacade(EObject umlOwner, EReference umlReference, EObject object) { - FacadeObject result = UMLRTFactory.create(object); + FacadeObject result = (object == null) ? null : UMLRTFactory.create(object); - if ((result == null) && (object.eResource() == null)) { + if ((result == null) && (object != null) && (object.eResource() == null)) { // If the object was destroyed, it may have lost its adapter, // so we need to scan List<? extends FacadeObject> search = getFacadeList(umlOwner, umlReference, object); @@ -389,7 +389,11 @@ protected void handleObjectReplaced(Notification msg, int position, EObject oldObject, EObject newObject) { FacadeObject oldFacade = getFacade(msg, oldObject); FacadeObject newFacade = getFacade(msg, newObject); - if ((oldFacade != null) && (newFacade != null)) { + + if (((oldFacade != null) || (oldObject == null)) + && ((newFacade != null) || (newObject == null))) { + // Be careful to to misinterpret the case where there was an old/new + // object that does not correspond to a façade object handleObjectReplaced(msg, position, oldFacade, newFacade); } else { handleObjectRemoved(msg, position, oldObject);
diff --git a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src/org/eclipse/papyrusrt/umlrt/uml/internal/util/InheritanceAdapter.java b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src/org/eclipse/papyrusrt/umlrt/uml/internal/util/InheritanceAdapter.java index 18cd9e0..f168694 100644 --- a/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src/org/eclipse/papyrusrt/umlrt/uml/internal/util/InheritanceAdapter.java +++ b/plugins/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml/src/org/eclipse/papyrusrt/umlrt/uml/internal/util/InheritanceAdapter.java
@@ -40,6 +40,7 @@ import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.Capsule; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.CapsulePart; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.Protocol; +import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.ProtocolContainer; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTConnector; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTMessageSet; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTPort; @@ -66,6 +67,7 @@ import org.eclipse.papyrusrt.umlrt.uml.util.UMLRTExtensionUtil; import org.eclipse.uml2.uml.Class; import org.eclipse.uml2.uml.Classifier; +import org.eclipse.uml2.uml.Collaboration; import org.eclipse.uml2.uml.Connector; import org.eclipse.uml2.uml.Constraint; import org.eclipse.uml2.uml.Generalization; @@ -900,9 +902,16 @@ switch (stereotypeApplication.eClass().getClassifierID()) { case UMLRealTimePackage.CAPSULE: { Capsule capsule = (Capsule) stereotypeApplication; - if (capsule.getBase_Class() != null) { + Class base = capsule.getBase_Class(); + if (base != null) { // Initialize it - getClassifierAdapter().adapt(capsule.getBase_Class()); + getClassifierAdapter().adapt(base); + + // Kick the package façade, if any + org.eclipse.uml2.uml.Package package_ = base.getNearestPackage(); + if (package_ != null) { + FacadeAdapter.getInstance(package_).ifPresent(a -> a.tickle(base)); + } } break; } @@ -947,9 +956,19 @@ } case UMLRealTimePackage.PROTOCOL: { Protocol protocol = (Protocol) stereotypeApplication; - if (protocol.getBase_Collaboration() != null) { + Collaboration base = protocol.getBase_Collaboration(); + if (base != null) { // Initialize it - getClassifierAdapter().adapt(protocol.getBase_Collaboration()); + getClassifierAdapter().adapt(base); + + // Kick the package façade, if any + org.eclipse.uml2.uml.Package package_ = base.getNearestPackage(); + if (package_ != null) { + package_ = package_.getNestingPackage(); + if (package_ != null) { + FacadeAdapter.getInstance(package_).ifPresent(a -> a.tickle(base)); + } + } } break; } @@ -961,7 +980,18 @@ } break; } - // TODO etc. + case UMLRealTimePackage.PROTOCOL_CONTAINER: { + ProtocolContainer protocolContainer = (ProtocolContainer) stereotypeApplication; + org.eclipse.uml2.uml.Package base = protocolContainer.getBase_Package(); + if (base != null) { + // Kick the containing package façade, if any + org.eclipse.uml2.uml.Package package_ = base.getNestingPackage(); + if (package_ != null) { + FacadeAdapter.getInstance(package_).ifPresent(a -> a.tickle(base)); + } + } + break; + } } }
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/CapsuleFacadeNotificationTest.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/CapsuleFacadeNotificationTest.java new file mode 100644 index 0000000..b1cb247 --- /dev/null +++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/CapsuleFacadeNotificationTest.java
@@ -0,0 +1,113 @@ +/***************************************************************************** + * Copyright (c) 2017 Christian W. Damus and others. + * + * 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: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrusrt.umlrt.uml.tests; + +import static org.hamcrest.CoreMatchers.is; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsulePart; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTConnector; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTPort; +import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.CapsuleTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.FacadeTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.ModelFixture; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.TestModel; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * Test cases for notifications in the capsule façade class {@link UMLRTCapsule}. + */ +@TestModel("inheritance/ports.uml") +@Category({ CapsuleTests.class, FacadeTests.class }) +public class CapsuleFacadeNotificationTest { + + @Rule + public final ModelFixture fixture = new ModelFixture(); + + public CapsuleFacadeNotificationTest() { + super(); + } + + @Test + public void nameNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + + fixture.expectNotification(capsule, UMLRTUMLRTPackage.Literals.NAMED_ELEMENT__NAME, Notification.SET, + is("RootCapsule"), is("NewName"), () -> capsule.toUML().setName("NewName")); + } + + @Test + public void portNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + + UMLRTPort[] newPort = { null }; + capsule.getPorts(); // Make sure the list exists to notify + + fixture.expectNotification(capsule, UMLRTUMLRTPackage.Literals.CAPSULE__PORT, Notification.ADD, + null, fixture.defer(() -> is(newPort[0])), () -> newPort[0] = capsule.createPort(capsule.getPackage().getProtocol("Protocol1"))); + + fixture.expectNotification(capsule, UMLRTUMLRTPackage.Literals.CAPSULE__PORT, Notification.REMOVE, + is(newPort[0]), null, newPort[0]::destroy); + } + + @Test + @TestModel("inheritance/parts.uml") + public void capsulePartNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + + UMLRTCapsulePart[] newPart = { null }; + capsule.getCapsuleParts(); // Make sure the list exists to notify + + fixture.expectNotification(capsule, UMLRTUMLRTPackage.Literals.CAPSULE__CAPSULE_PART, Notification.ADD, + null, fixture.defer(() -> is(newPart[0])), () -> newPart[0] = capsule.createCapsulePart(capsule.getPackage().getCapsule("Capsule2"))); + + fixture.expectNotification(capsule, UMLRTUMLRTPackage.Literals.CAPSULE__CAPSULE_PART, Notification.REMOVE, + is(newPart[0]), null, newPart[0]::destroy); + } + + @Test + @TestModel("inheritance/connectors.uml") + public void connectorNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPorts().get(0); + UMLRTCapsulePart part = capsule.getCapsuleParts().get(0); + UMLRTCapsule nested = part.getType(); + + UMLRTConnector[] newConnector = { null }; + capsule.getConnectors(); // Make sure the list exists to notify + + fixture.expectNotification(capsule, UMLRTUMLRTPackage.Literals.CAPSULE__CONNECTOR, Notification.ADD, + null, fixture.defer(() -> is(newConnector[0])), + () -> newConnector[0] = capsule.createConnector("NewConnector", port, null, nested.getPorts().get(0), part)); + + fixture.expectNotification(capsule, UMLRTUMLRTPackage.Literals.CAPSULE__CONNECTOR, Notification.REMOVE, + is(newConnector[0]), null, newConnector[0]::destroy); + } + + @Test + public void setSuperCapsule() { + UMLRTPackage model = UMLRTPackage.getInstance(fixture.getModel()); + UMLRTCapsule capsule = model.getCapsule("RootCapsule"); + UMLRTCapsule subcapsule = model.getCapsule("Subcapsule"); + UMLRTCapsule subsubcapsule = model.getCapsule("Subsubcapsule"); + + fixture.expectNotification(subsubcapsule, UMLRTUMLRTPackage.Literals.CAPSULE__SUPERCLASS, Notification.SET, + is(subcapsule), is(capsule), () -> subsubcapsule.toUML().getGeneralizations().get(0).setGeneral(capsule.toUML())); + } +}
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/CapsulePartNotificationTest.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/CapsulePartNotificationTest.java new file mode 100644 index 0000000..3775717 --- /dev/null +++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/CapsulePartNotificationTest.java
@@ -0,0 +1,197 @@ +/***************************************************************************** + * Copyright (c) 2017 Christian W. Damus and others. + * + * 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: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrusrt.umlrt.uml.tests; + +import static org.hamcrest.CoreMatchers.anything; +import static org.hamcrest.CoreMatchers.is; + +import java.util.List; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsulePart; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsulePartKind; +import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.CapsuleTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.FacadeTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.ModelFixture; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.TestModel; +import org.eclipse.uml2.uml.AggregationKind; +import org.eclipse.uml2.uml.MultiplicityElement; +import org.eclipse.uml2.uml.OpaqueExpression; +import org.eclipse.uml2.uml.UMLPackage; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * Test cases for notifications in the capsule façade class {@link UMLRTCapsulePart}. + */ +@TestModel("inheritance/parts.uml") +@Category({ CapsuleTests.class, FacadeTests.class }) +public class CapsulePartNotificationTest { + + @Rule + public final ModelFixture fixture = new ModelFixture(); + + public CapsulePartNotificationTest() { + super(); + } + + @Test + public void nameNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTCapsulePart part = capsule.getCapsulePart("capsule2"); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.NAMED_ELEMENT__NAME, Notification.SET, + is("capsule2"), is("newName"), () -> part.toUML().setName("newName")); + } + + @Test + public void typeNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTCapsule capsule4 = UMLRTCapsule.getInstance(fixture.getElement("Capsule4")); + UMLRTCapsulePart part = capsule.getCapsulePart("capsule2"); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.CAPSULE_PART__TYPE, Notification.SET, + is(part.getType()), is(capsule4), () -> part.toUML().setType(capsule4.toUML())); + } + + @Test + public void optionalNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTCapsulePart part = capsule.getCapsulePart("capsule2"); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.CAPSULE_PART__OPTIONAL, Notification.SET, + is(false), is(true), () -> part.toUML().setLower(0)); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.CAPSULE_PART__OPTIONAL, Notification.SET, + is(true), is(false), () -> part.toUML().setLower(1)); + + fixture.expectNoNotification(part, UMLRTUMLRTPackage.Literals.CAPSULE_PART__OPTIONAL, Notification.SET, + anything(), anything(), () -> destroyReplication(part.toUML())); + } + + @Test + public void replicationNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTCapsulePart part = capsule.getCapsulePart("capsule2"); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR, Notification.SET, + anything(), is(3), () -> setReplication(part.toUML(), 3)); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR, Notification.SET, + is(3), is(1), () -> setReplication(part.toUML(), 1)); + + fixture.expectNoNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR, Notification.SET, + anything(), anything(), () -> destroyReplication(part.toUML())); + } + + @Test + public void replicationAsStringNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTCapsulePart part = capsule.getCapsulePart("capsule2"); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + anything(), is("3"), () -> setReplication(part.toUML(), 3)); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + is("3"), is("1"), () -> setReplication(part.toUML(), 1)); + + fixture.expectNoNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + anything(), anything(), () -> destroyReplication(part.toUML())); + } + + @Test + public void symbolicReplicationNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTCapsulePart part = capsule.getCapsulePart("capsule2"); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + anything(), is("MAX_PARTS"), () -> setReplication(part.toUML(), "MAX_PARTS")); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + is("MAX_PARTS"), is("NUM_PARTS"), () -> setReplication(part.toUML(), "NUM_PARTS")); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + is("NUM_PARTS"), is("1"), () -> destroyReplication(part.toUML())); + } + + @Test + public void kindNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTCapsulePart part = capsule.getCapsulePart("capsule2"); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.CAPSULE_PART__KIND, Notification.SET, + is(UMLRTCapsulePartKind.FIXED), is(UMLRTCapsulePartKind.OPTIONAL), + () -> part.toUML().setLower(0)); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.CAPSULE_PART__KIND, Notification.SET, + is(UMLRTCapsulePartKind.OPTIONAL), is(UMLRTCapsulePartKind.PLUG_IN), + () -> part.toUML().setAggregation(AggregationKind.SHARED_LITERAL)); + + fixture.expectNotification(part, UMLRTUMLRTPackage.Literals.CAPSULE_PART__KIND, Notification.SET, + is(UMLRTCapsulePartKind.PLUG_IN), is(UMLRTCapsulePartKind.FIXED), + () -> destroyReplication(part.toUML())); + + // Fixed doesn't care about aggregation + fixture.expectNoNotification(part, UMLRTUMLRTPackage.Literals.CAPSULE_PART__KIND, Notification.SET, + anything(), anything(), + () -> part.toUML().setAggregation(AggregationKind.COMPOSITE_LITERAL)); + } + + // + // Test framework + // + + void setReplication(MultiplicityElement mult, int replication) { + mult.setLower(replication); + mult.setUpper(replication); + } + + void setReplication(MultiplicityElement mult, String replication) { + if (mult.getLowerValue() instanceof OpaqueExpression) { + List<String> body = ((OpaqueExpression) mult.getLowerValue()).getBodies(); + if (body.isEmpty()) { + body.add(replication); + } else { + body.set(0, replication); + } + } else { + ((OpaqueExpression) mult.createLowerValue(null, null, UMLPackage.Literals.OPAQUE_EXPRESSION)) + .getBodies().add(replication); + } + + if (mult.getUpperValue() instanceof OpaqueExpression) { + List<String> body = ((OpaqueExpression) mult.getUpperValue()).getBodies(); + if (body.isEmpty()) { + body.add(replication); + } else { + body.set(0, replication); + } + } else { + ((OpaqueExpression) mult.createUpperValue(null, null, UMLPackage.Literals.OPAQUE_EXPRESSION)) + .getBodies().add(replication); + } + } + + void destroyReplication(MultiplicityElement mult) { + if (mult.getLowerValue() != null) { + mult.getLowerValue().destroy(); + } + if (mult.getUpperValue() != null) { + mult.getUpperValue().destroy(); + } + } +}
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ConnectorNotificationTest.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ConnectorNotificationTest.java new file mode 100644 index 0000000..ce58097 --- /dev/null +++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ConnectorNotificationTest.java
@@ -0,0 +1,169 @@ +/***************************************************************************** + * Copyright (c) 2017 Christian W. Damus and others. + * + * 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: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrusrt.umlrt.uml.tests; + +import static org.hamcrest.CoreMatchers.anything; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; + +import java.util.List; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsulePart; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTConnector; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTPort; +import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.CapsuleTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.FacadeTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.ModelFixture; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.TestModel; +import org.eclipse.uml2.uml.MultiplicityElement; +import org.eclipse.uml2.uml.OpaqueExpression; +import org.eclipse.uml2.uml.UMLPackage; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * Test cases for notifications in the capsule façade class {@link UMLRTConnector}. + */ +@TestModel("inheritance/connectors.uml") +@Category({ CapsuleTests.class, FacadeTests.class }) +public class ConnectorNotificationTest { + + @Rule + public final ModelFixture fixture = new ModelFixture(); + + public ConnectorNotificationTest() { + super(); + } + + @Test + public void nameNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTConnector connector = capsule.getConnector("connector1"); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.NAMED_ELEMENT__NAME, Notification.SET, + is("connector1"), is("newName"), () -> connector.toUML().setName("newName")); + } + + @Test + public void sourceNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTConnector connector = capsule.getConnector("connector1"); + UMLRTPort port = capsule.getPort("protocol2"); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.CONNECTOR__SOURCE, Notification.SET, + is(connector.getSource()), is(port), () -> connector.toUML().getEnds().get(0).setRole(port.toUML())); + } + + @Test + public void sourcePartWithPortNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTConnector connector = capsule.getConnector("connector1"); + UMLRTCapsulePart part = capsule.getCapsulePart("nestedCapsule"); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.CONNECTOR__SOURCE_PART_WITH_PORT, Notification.SET, + nullValue(), is(part), () -> connector.toUML().getEnds().get(0).setPartWithPort(part.toUML())); + } + + @Test + public void targetNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTConnector connector = capsule.getConnector("connector1"); + UMLRTPort port = capsule.getPort("protocol2"); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.CONNECTOR__TARGET, Notification.SET, + is(connector.getTarget()), is(port), () -> connector.toUML().getEnds().get(1).setRole(port.toUML())); + } + + @Test + public void targetPartWithPortNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTConnector connector = capsule.getConnector("connector1"); + UMLRTCapsulePart part = capsule.getCapsulePart("nestedCapsule"); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.CONNECTOR__TARGET_PART_WITH_PORT, Notification.SET, + is(part), nullValue(), () -> connector.toUML().getEnds().get(1).setPartWithPort(null)); + } + + @Test + public void sourceReplicationNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTConnector connector = capsule.getConnector("connector1"); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.CONNECTOR__SOURCE_REPLICATION_FACTOR, Notification.SET, + anything(), is(3), () -> setReplication(connector.toUML().getEnds().get(0), 3)); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.CONNECTOR__SOURCE_REPLICATION_FACTOR, Notification.SET, + is(3), is(1), () -> destroyReplication(connector.toUML().getEnds().get(0))); + } + + @Test + public void targetReplicationNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTConnector connector = capsule.getConnector("connector1"); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.CONNECTOR__TARGET_REPLICATION_FACTOR, Notification.SET, + anything(), is(3), () -> setReplication(connector.toUML().getEnds().get(1), 3)); + + fixture.expectNotification(connector, UMLRTUMLRTPackage.Literals.CONNECTOR__TARGET_REPLICATION_FACTOR, Notification.SET, + is(3), is(1), () -> destroyReplication(connector.toUML().getEnds().get(1))); + } + + // + // Test framework + // + + void setReplication(MultiplicityElement mult, int replication) { + mult.setLower(replication); + mult.setUpper(replication); + } + + void setReplication(MultiplicityElement mult, String replication) { + if (mult.getLowerValue() instanceof OpaqueExpression) { + List<String> body = ((OpaqueExpression) mult.getLowerValue()).getBodies(); + if (body.isEmpty()) { + body.add(replication); + } else { + body.set(0, replication); + } + } else { + ((OpaqueExpression) mult.createLowerValue(null, null, UMLPackage.Literals.OPAQUE_EXPRESSION)) + .getBodies().add(replication); + } + + if (mult.getUpperValue() instanceof OpaqueExpression) { + List<String> body = ((OpaqueExpression) mult.getUpperValue()).getBodies(); + if (body.isEmpty()) { + body.add(replication); + } else { + body.set(0, replication); + } + } else { + ((OpaqueExpression) mult.createUpperValue(null, null, UMLPackage.Literals.OPAQUE_EXPRESSION)) + .getBodies().add(replication); + } + } + + void destroyReplication(MultiplicityElement mult) { + if (mult.getLowerValue() != null) { + mult.getLowerValue().destroy(); + } + if (mult.getUpperValue() != null) { + mult.getUpperValue().destroy(); + } + } +}
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/PackageFacadeNotificationTest.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/PackageFacadeNotificationTest.java new file mode 100644 index 0000000..543bc02 --- /dev/null +++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/PackageFacadeNotificationTest.java
@@ -0,0 +1,94 @@ +/***************************************************************************** + * Copyright (c) 2017 Christian W. Damus and others. + * + * 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: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrusrt.umlrt.uml.tests; + +import static org.hamcrest.CoreMatchers.is; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTProtocol; +import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.CapsuleTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.FacadeTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.ModelFixture; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.TestModel; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * Test cases for notifications in the façade class {@link UMLRTPackage}. + */ +@TestModel("inheritance/ports.uml") +@Category({ CapsuleTests.class, FacadeTests.class }) +public class PackageFacadeNotificationTest { + + @Rule + public final ModelFixture fixture = new ModelFixture(); + + public PackageFacadeNotificationTest() { + super(); + } + + @Test + public void nameNotifications() { + UMLRTPackage package_ = fixture.getRoot(); + + fixture.expectNotification(package_, UMLRTUMLRTPackage.Literals.NAMED_ELEMENT__NAME, Notification.SET, + is("ports"), is("NewName"), () -> package_.toUML().setName("NewName")); + } + + @Test + public void nestedPackageNotifications() { + UMLRTPackage package_ = fixture.getRoot(); + + UMLRTPackage[] newPackage = { null }; + package_.getNestedPackages(); // Make sure the list exists to notify + + fixture.expectNotification(package_, UMLRTUMLRTPackage.Literals.PACKAGE__NESTED_PACKAGE, Notification.ADD, + null, fixture.defer(() -> is(newPackage[0])), () -> newPackage[0] = package_.createNestedPackage("NewPackage")); + + fixture.expectNotification(package_, UMLRTUMLRTPackage.Literals.PACKAGE__NESTED_PACKAGE, Notification.REMOVE, + is(newPackage[0]), null, newPackage[0]::destroy); + } + + @Test + public void capsuleNotifications() { + UMLRTPackage package_ = fixture.getRoot(); + + UMLRTCapsule[] newCapsule = { null }; + package_.getCapsules(); // Make sure the list exists to notify + + fixture.expectNotification(package_, UMLRTUMLRTPackage.Literals.PACKAGE__CAPSULE, Notification.ADD, + null, fixture.defer(() -> is(newCapsule[0])), () -> newCapsule[0] = package_.createCapsule("NewCapsule")); + + fixture.expectNotification(package_, UMLRTUMLRTPackage.Literals.PACKAGE__CAPSULE, Notification.REMOVE, + is(newCapsule[0]), null, newCapsule[0]::destroy); + } + + @Test + public void protocolNotifications() { + UMLRTPackage package_ = fixture.getRoot(); + + UMLRTProtocol[] newProtocol = { null }; + package_.getProtocols(); // Make sure the list exists to notify + + fixture.expectNotification(package_, UMLRTUMLRTPackage.Literals.PACKAGE__PROTOCOL, Notification.ADD, + null, fixture.defer(() -> is(newProtocol[0])), () -> newProtocol[0] = package_.createProtocol("NewProtocol")); + + fixture.expectNotification(package_, UMLRTUMLRTPackage.Literals.PACKAGE__PROTOCOL, Notification.REMOVE, + is(newProtocol[0]), null, newProtocol[0]::destroy); + } +}
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/PortFacadeNotificationTest.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/PortFacadeNotificationTest.java new file mode 100644 index 0000000..046e97f --- /dev/null +++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/PortFacadeNotificationTest.java
@@ -0,0 +1,297 @@ +/***************************************************************************** + * Copyright (c) 2017 Christian W. Damus and others. + * + * 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: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrusrt.umlrt.uml.tests; + +import static org.hamcrest.CoreMatchers.anything; +import static org.hamcrest.CoreMatchers.is; + +import java.util.List; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.PortRegistrationType; +import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTPort; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTCapsule; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTPort; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTPortKind; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTProtocol; +import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.CapsuleTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.FacadeTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.ModelFixture; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.TestModel; +import org.eclipse.uml2.uml.MultiplicityElement; +import org.eclipse.uml2.uml.OpaqueExpression; +import org.eclipse.uml2.uml.UMLPackage; +import org.eclipse.uml2.uml.util.UMLUtil; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * Test cases for notifications in the capsule façade class {@link UMLRTPort}. + */ +@TestModel("inheritance/ports.uml") +@Category({ CapsuleTests.class, FacadeTests.class }) +public class PortFacadeNotificationTest { + + @Rule + public final ModelFixture fixture = new ModelFixture(); + + public PortFacadeNotificationTest() { + super(); + } + + @Test + public void nameNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.NAMED_ELEMENT__NAME, Notification.SET, + is("protocol1"), is("newName"), () -> port.toUML().setName("newName")); + } + + @Test + public void typeNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + UMLRTProtocol protocol2 = capsule.getPackage().getProtocol("Protocol2"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__TYPE, Notification.SET, + is(port.getType()), is(protocol2), () -> port.toUML().setType(protocol2.toUML())); + } + + @Test + public void replicationNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR, Notification.SET, + anything(), is(3), () -> setReplication(port.toUML(), 3)); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR, Notification.SET, + is(3), is(1), () -> setReplication(port.toUML(), 1)); + + fixture.expectNoNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR, Notification.SET, + anything(), anything(), () -> destroyReplication(port.toUML())); + } + + @Test + public void replicationAsStringNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + anything(), is("3"), () -> setReplication(port.toUML(), 3)); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + is("3"), is("1"), () -> setReplication(port.toUML(), 1)); + + fixture.expectNoNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + anything(), anything(), () -> destroyReplication(port.toUML())); + } + + @Test + public void symbolicReplicationNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + anything(), is("MAX_PARTS"), () -> setReplication(port.toUML(), "MAX_PARTS")); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + is("MAX_PARTS"), is("NUM_PARTS"), () -> setReplication(port.toUML(), "NUM_PARTS")); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.REPLICATED_ELEMENT__REPLICATION_FACTOR_AS_STRING, Notification.SET, + is("NUM_PARTS"), is("1"), () -> destroyReplication(port.toUML())); + } + + @Test + public void conjugateNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__CONJUGATED, Notification.SET, + is(port.isConjugated()), is(!port.isConjugated()), + () -> port.toUML().setIsConjugated(!port.toUML().isConjugated())); + } + + @Test + public void conjugateTypeNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__TYPE, Notification.SET, + is(port.getType()), is(port.getType().getConjugate()), + () -> port.toUML().setIsConjugated(!port.toUML().isConjugated())); + } + + @Test + public void behaviorNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__BEHAVIOR, Notification.SET, + is(port.isBehavior()), is(!port.isBehavior()), + () -> port.toUML().setIsBehavior(!port.toUML().isBehavior())); + } + + @Test + public void serviceNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__SERVICE, Notification.SET, + is(port.isService()), is(!port.isService()), + () -> port.toUML().setIsService(!port.toUML().isService())); + } + + @Test + public void wiredNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + RTPort stereo = UMLUtil.getStereotypeApplication(port.toUML(), RTPort.class); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__WIRED, Notification.SET, + is(port.isWired()), is(!port.isWired()), + () -> stereo.setIsWired(!stereo.isWired())); + } + + @Test + public void publishNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + RTPort stereo = UMLUtil.getStereotypeApplication(port.toUML(), RTPort.class); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__PUBLISH, Notification.SET, + is(port.isPublish()), is(!port.isPublish()), + () -> stereo.setIsPublish(!stereo.isPublish())); + } + + @Test + public void notificationNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + RTPort stereo = UMLUtil.getStereotypeApplication(port.toUML(), RTPort.class); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__NOTIFICATION, Notification.SET, + is(port.isNotification()), is(!port.isNotification()), + () -> stereo.setIsNotification(!stereo.isNotification())); + } + + @Test + public void registrationNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + RTPort stereo = UMLUtil.getStereotypeApplication(port.toUML(), RTPort.class); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__REGISTRATION, Notification.SET, + is(stereo.getRegistration()), is(PortRegistrationType.AUTOMATIC_LOCKED), + () -> stereo.setRegistration(PortRegistrationType.AUTOMATIC_LOCKED)); + } + + @Test + public void registrationOverrideNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + RTPort stereo = UMLUtil.getStereotypeApplication(port.toUML(), RTPort.class); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__REGISTRATION_OVERRIDE, Notification.SET, + is(""), is("whatever"), + () -> stereo.setRegistrationOverride("whatever")); + } + + @Test + public void kindNotifications() { + UMLRTCapsule capsule = UMLRTCapsule.getInstance(fixture.getElement("RootCapsule")); + UMLRTPort port = capsule.getPort("protocol1"); + RTPort stereo = UMLUtil.getStereotypeApplication(port.toUML(), RTPort.class); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__KIND, Notification.SET, + is(UMLRTPortKind.EXTERNAL_BEHAVIOR), is(UMLRTPortKind.RELAY), + () -> port.toUML().setIsBehavior(false)); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__KIND, Notification.SET, + is(UMLRTPortKind.RELAY), is(UMLRTPortKind.EXTERNAL_BEHAVIOR), + () -> port.toUML().setIsBehavior(true)); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__KIND, Notification.SET, + is(UMLRTPortKind.EXTERNAL_BEHAVIOR), is(UMLRTPortKind.INTERNAL_BEHAVIOR), + () -> port.toUML().setIsService(false)); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__KIND, Notification.SET, + is(UMLRTPortKind.INTERNAL_BEHAVIOR), is(UMLRTPortKind.SAP), + () -> stereo.setIsWired(false)); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__KIND, Notification.SET, + is(UMLRTPortKind.SAP), is(UMLRTPortKind.SPP), + () -> stereo.setIsPublish(true)); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__KIND, Notification.SET, + is(UMLRTPortKind.SPP), is(UMLRTPortKind.NULL), + () -> stereo.setIsWired(true)); + + // The isService is still false! + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__KIND, Notification.SET, + is(UMLRTPortKind.NULL), is(UMLRTPortKind.INTERNAL_BEHAVIOR), + () -> stereo.setIsPublish(false)); + + fixture.expectNotification(port, UMLRTUMLRTPackage.Literals.PORT__KIND, Notification.SET, + is(UMLRTPortKind.INTERNAL_BEHAVIOR), is(UMLRTPortKind.EXTERNAL_BEHAVIOR), + () -> port.toUML().setIsService(true)); + } + + // + // Test framework + // + + void setReplication(MultiplicityElement mult, int replication) { + mult.setLower(replication); + mult.setUpper(replication); + } + + void setReplication(MultiplicityElement mult, String replication) { + if (mult.getLowerValue() instanceof OpaqueExpression) { + List<String> body = ((OpaqueExpression) mult.getLowerValue()).getBodies(); + if (body.isEmpty()) { + body.add(replication); + } else { + body.set(0, replication); + } + } else { + ((OpaqueExpression) mult.createLowerValue(null, null, UMLPackage.Literals.OPAQUE_EXPRESSION)) + .getBodies().add(replication); + } + + if (mult.getUpperValue() instanceof OpaqueExpression) { + List<String> body = ((OpaqueExpression) mult.getUpperValue()).getBodies(); + if (body.isEmpty()) { + body.add(replication); + } else { + body.set(0, replication); + } + } else { + ((OpaqueExpression) mult.createUpperValue(null, null, UMLPackage.Literals.OPAQUE_EXPRESSION)) + .getBodies().add(replication); + } + } + + void destroyReplication(MultiplicityElement mult) { + if (mult.getLowerValue() != null) { + mult.getLowerValue().destroy(); + } + if (mult.getUpperValue() != null) { + mult.getUpperValue().destroy(); + } + } +}
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolFacadeNotificationTest.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolFacadeNotificationTest.java new file mode 100644 index 0000000..af2bbfb --- /dev/null +++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolFacadeNotificationTest.java
@@ -0,0 +1,93 @@ +/***************************************************************************** + * Copyright (c) 2017 Christian W. Damus and others. + * + * 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: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrusrt.umlrt.uml.tests; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTMessageKind; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTProtocol; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTProtocolMessage; +import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.FacadeTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.ProtocolTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.ModelFixture; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.TestModel; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * Test cases for notifications in the protocol façade class {@link UMLRTProtocol}. + */ +@TestModel("inheritance/ports.uml") +@Category({ ProtocolTests.class, FacadeTests.class }) +public class ProtocolFacadeNotificationTest { + + @Rule + public final ModelFixture fixture = new ModelFixture(); + + public ProtocolFacadeNotificationTest() { + super(); + } + + @Test + public void nameNotifications() { + UMLRTProtocol protocol = fixture.getRoot().getProtocol("Protocol1"); + + fixture.expectNotification(protocol, UMLRTUMLRTPackage.Literals.NAMED_ELEMENT__NAME, Notification.SET, + is("Protocol1"), is("NewName"), () -> protocol.toUML().setName("NewName")); + } + + @Test + public void inMessageNotifications() { + messageNotifications(RTMessageKind.IN, UMLRTUMLRTPackage.Literals.PROTOCOL__IN_MESSAGE); + } + + void messageNotifications(RTMessageKind kind, EReference reference) { + UMLRTProtocol protocol = fixture.getRoot().getProtocol("Protocol1"); + + UMLRTProtocolMessage[] newMessage = { null }; + ((EObject) protocol).eGet(reference); // Make sure the list exists to notify + + fixture.expectNotification(protocol, reference, Notification.ADD, + null, fixture.defer(() -> is(newMessage[0])), + () -> newMessage[0] = protocol.createMessage(kind, "newMsg")); + + fixture.expectNotification(protocol, reference, Notification.REMOVE, + is(newMessage[0]), null, newMessage[0]::destroy); + } + + @Test + public void outMessageNotifications() { + messageNotifications(RTMessageKind.OUT, UMLRTUMLRTPackage.Literals.PROTOCOL__OUT_MESSAGE); + } + + @Test + public void inOutMessageNotifications() { + messageNotifications(RTMessageKind.IN_OUT, UMLRTUMLRTPackage.Literals.PROTOCOL__IN_OUT_MESSAGE); + } + + @Test + public void setSuperProtocol() { + UMLRTProtocol protocol1 = fixture.getRoot().getProtocol("Protocol1"); + UMLRTProtocol protocol2 = fixture.getRoot().getProtocol("Protocol2"); + + fixture.expectNotification(protocol2, UMLRTUMLRTPackage.Literals.PROTOCOL__SUPER_PROTOCOL, Notification.SET, + nullValue(), is(protocol1), () -> protocol2.toUML().createGeneralization(protocol1.toUML())); + } +}
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolMessageFacadeNotificationTest.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolMessageFacadeNotificationTest.java new file mode 100644 index 0000000..9e31ed8 --- /dev/null +++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/ProtocolMessageFacadeNotificationTest.java
@@ -0,0 +1,94 @@ +/***************************************************************************** + * Copyright (c) 2017 Christian W. Damus and others. + * + * 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: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrusrt.umlrt.uml.tests; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTMessageKind; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTProtocol; +import org.eclipse.papyrusrt.umlrt.uml.UMLRTProtocolMessage; +import org.eclipse.papyrusrt.umlrt.uml.internal.facade.UMLRTUMLRTPackage; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.FacadeTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.categories.ProtocolTests; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.ModelFixture; +import org.eclipse.papyrusrt.umlrt.uml.tests.util.TestModel; +import org.eclipse.uml2.uml.Interface; +import org.eclipse.uml2.uml.Parameter; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +/** + * Test cases for notifications in the protocol façade class {@link UMLRTProtocolMessage}. + */ +@TestModel("inheritance/ports.uml") +@Category({ ProtocolTests.class, FacadeTests.class }) +public class ProtocolMessageFacadeNotificationTest { + + @Rule + public final ModelFixture fixture = new ModelFixture(); + + public ProtocolMessageFacadeNotificationTest() { + super(); + } + + @Test + public void nameNotifications() { + UMLRTProtocol protocol = fixture.getRoot().getProtocol("Protocol1"); + UMLRTProtocolMessage message = protocol.getInMessage("greet"); + + fixture.expectNotification(message, UMLRTUMLRTPackage.Literals.NAMED_ELEMENT__NAME, Notification.SET, + is("greet"), is("sayHello"), () -> message.toUML().setName("sayHello")); + } + + @Test + public void parameterNotifications() { + UMLRTProtocol protocol = fixture.getRoot().getProtocol("Protocol1"); + UMLRTProtocolMessage message = protocol.getInMessage("greet"); + + Parameter[] newParam = { null }; + + fixture.expectNotification(message, UMLRTUMLRTPackage.Literals.PROTOCOL_MESSAGE__PARAMETER, Notification.ADD, + nullValue(), fixture.defer(() -> is(newParam[0])), + () -> newParam[0] = message.createParameter("whatToSay", null)); + + fixture.expectNotification(message, UMLRTUMLRTPackage.Literals.PROTOCOL_MESSAGE__PARAMETER, Notification.REMOVE, + is(newParam[0]), nullValue(), + () -> newParam[0].destroy()); + } + + @Test + public void kindNotifications() { + UMLRTProtocol protocol = fixture.getRoot().getProtocol("Protocol1"); + UMLRTProtocolMessage message = protocol.getInMessage("greet"); + + Interface messageSetIn = fixture.getElement("Protocol1::Protocol1", Interface.class); + Interface messageSetOut = fixture.getElement("Protocol1::Protocol1~", Interface.class); + Interface messageSetInOut = fixture.getElement("Protocol1::Protocol1IO", Interface.class); + + fixture.expectNotification(message, UMLRTUMLRTPackage.Literals.PROTOCOL_MESSAGE__KIND, Notification.SET, + is(RTMessageKind.IN), is(RTMessageKind.IN_OUT), + () -> messageSetInOut.getOwnedOperations().add(message.toUML())); + + fixture.expectNotification(message, UMLRTUMLRTPackage.Literals.PROTOCOL_MESSAGE__KIND, Notification.SET, + is(RTMessageKind.IN_OUT), is(RTMessageKind.OUT), + () -> messageSetOut.getOwnedOperations().add(message.toUML())); + + fixture.expectNotification(message, UMLRTUMLRTPackage.Literals.PROTOCOL_MESSAGE__KIND, Notification.SET, + is(RTMessageKind.OUT), is(RTMessageKind.IN), + () -> messageSetIn.getOwnedOperations().add(message.toUML())); + } +}
diff --git a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/util/ModelFixture.java b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/util/ModelFixture.java index 80f8876..ccb91e2 100644 --- a/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/util/ModelFixture.java +++ b/tests/junit/umlrt/profile/org.eclipse.papyrusrt.umlrt.uml.tests/src/org/eclipse/papyrusrt/umlrt/uml/tests/util/ModelFixture.java
@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation; import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -29,6 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -51,6 +53,7 @@ import org.eclipse.emf.edit.provider.IItemLabelProvider; import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.UMLRealTimePackage; +import org.eclipse.papyrusrt.umlrt.uml.FacadeObject; import org.eclipse.papyrusrt.umlrt.uml.UMLRTPackage; import org.eclipse.papyrusrt.umlrt.uml.internal.impl.InternalUMLRTElement; import org.eclipse.papyrusrt.umlrt.uml.util.UMLRTResourcesUtil; @@ -60,6 +63,7 @@ import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.UMLPackage; import org.eclipse.uml2.uml.edit.providers.UMLItemProviderAdapterFactory; +import org.hamcrest.BaseMatcher; import org.hamcrest.Matcher; import org.hamcrest.StringDescription; import org.hamcrest.core.IsAnything; @@ -74,12 +78,15 @@ * @see TestModel */ public class ModelFixture extends TestWatcher { + private static final Object TEST_DEFERRED = new Object(); private String testModelPath; private ResourceSet resourceSet; private Package testModel; private AdapterFactory adapterFactory; + private List<Matcher<Object>> deferred; + /** * Initializes me. I will get the test model from an annotation. * @@ -240,6 +247,11 @@ protected void finished(Description description) { if (resourceSet != null) { try { + // Check deferred assertions + if (deferred != null) { + deferred.forEach(m -> assertThat(TEST_DEFERRED, m)); + } + // Check that nothing accidentally created the wrong kind of model element assertModelImplementationOverrides(); @@ -365,12 +377,24 @@ expectNotification(notifier, feature, eventType, oldValueMatcher, newValueMatcher, script, true); } + public <T> void expectNotification(FacadeObject notifier, Object feature, int eventType, + Matcher<T> oldValueMatcher, Matcher<T> newValueMatcher, Runnable script) { + + expectNotification((EObject) notifier, feature, eventType, oldValueMatcher, newValueMatcher, script); + } + public <T> void expectNoNotification(Notifier notifier, Object feature, int eventType, Matcher<T> oldValueMatcher, Matcher<T> newValueMatcher, Runnable script) { expectNotification(notifier, feature, eventType, oldValueMatcher, newValueMatcher, script, false); } + public <T> void expectNoNotification(FacadeObject notifier, Object feature, int eventType, + Matcher<T> oldValueMatcher, Matcher<T> newValueMatcher, Runnable script) { + + expectNoNotification((EObject) notifier, feature, eventType, oldValueMatcher, newValueMatcher, script); + } + private <T> void expectNotification(Notifier notifier, Object feature, int eventType, Matcher<T> oldValueMatcher, Matcher<T> newValueMatcher, Runnable script, boolean expected) { @@ -407,11 +431,21 @@ } }; - resourceSet.eAdapters().add(adapter); + if (notifier instanceof FacadeObject) { + // Façade objects are free-floating, so we can only attach + // adapters directly to them + notifier.eAdapters().add(adapter); + } else { + resourceSet.eAdapters().add(adapter); + } try { script.run(); } finally { - resourceSet.eAdapters().remove(adapter); + if (notifier instanceof FacadeObject) { + notifier.eAdapters().remove(adapter); + } else { + resourceSet.eAdapters().remove(adapter); + } } if (found.get() != expected) { @@ -451,4 +485,47 @@ private static boolean isTrivial(Matcher<?> matcher) { return (matcher == null) || (matcher instanceof IsAnything<?>); } + + @SuppressWarnings("unchecked") + public <T> Matcher<T> defer(Supplier<Matcher<T>> matcherSupplier) { + final List<Object> deferred = new ArrayList<>(); + + return new BaseMatcher<T>() { + { + if (ModelFixture.this.deferred == null) { + ModelFixture.this.deferred = new ArrayList<>(); + } + ModelFixture.this.deferred.add((Matcher<Object>) this); + } + + @Override + public void describeMismatch(Object item, org.hamcrest.Description description) { + if (deferred.isEmpty()) { + description.appendText("Deferred matcher was never asserted: "); + describeTo(description); + } else { + matcherSupplier.get().describeMismatch(deferred.get(0), description); + } + } + + @Override + public void describeTo(org.hamcrest.Description description) { + matcherSupplier.get().describeTo(description); + } + + @Override + public boolean matches(Object item) { + if (item == TEST_DEFERRED) { + return deferred.stream().anyMatch(matcherSupplier.get()::matches); + } else { + deferred.add(item); + return true; + } + } + }; + } + + public <T> Matcher<T> defer(Function<T, Matcher<T>> matcher, T expected) { + return defer(() -> matcher.apply(expected)); + } }