diff options
author | Christian W. Damus | 2017-01-31 02:03:47 +0000 |
---|---|---|
committer | Christian W. Damus | 2017-01-31 02:03:47 +0000 |
commit | df8a130a91d28b2db5f0ce676f3afb18f554fe5e (patch) | |
tree | ca9fa21a1653ddd8b526552389396b8e92b6c1f8 | |
parent | b5b400ba0e697f373f60c51a730c9845efda5f3e (diff) | |
download | org.eclipse.papyrus-rt-committers/cdamus/inheritance.tar.gz org.eclipse.papyrus-rt-committers/cdamus/inheritance.tar.xz org.eclipse.papyrus-rt-committers/cdamus/inheritance.zip |
Bug 510315: [UML-RT] UML specific implementation for state machinescommitters/cdamus/inheritance
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
22 files changed, 2380 insertions, 54 deletions
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 4d0ed4f38..1b09ad98c 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.Collections; 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 @@ public enum UMLRTCapsulePartKind implements Enumerator { } /** + * 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 eb4f6a0b5..eb844c50e 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 @@ public enum UMLRTPortKind implements Enumerator { } /** + * 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 9146b1667..aa0a85af4 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.Objects; 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 @@ public class UMLRTCapsuleImpl extends UMLRTClassifierImpl implements UMLRTCapsul 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 @@ public class UMLRTCapsuleImpl extends UMLRTClassifierImpl implements UMLRTCapsul || (reference == ExtUMLExtPackage.Literals.ENCAPSULATED_CLASSIFIER__IMPLICIT_PORT)) { result = get().ports; + } else { + result = super.getFacadeList(owner, reference, object); } return result; @@ -153,7 +166,10 @@ public class UMLRTCapsuleImpl extends UMLRTClassifierImpl implements UMLRTCapsul || (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 6ea25647f..c4155f994 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.Objects; 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 @@ public class UMLRTCapsulePartImpl extends UMLRTReplicatedElementImpl implements */ 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 @@ public class UMLRTCapsulePartImpl extends UMLRTReplicatedElementImpl implements 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 @@ public class UMLRTCapsulePartImpl extends UMLRTReplicatedElementImpl implements */ @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 ee40016fd..48ef65fa4 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.List; 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.common.util.DerivedUnionEObjectEList; 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 @@ import org.eclipse.uml2.uml.Generalization; * @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 @@ public abstract class UMLRTClassifierImpl extends UMLRTNamedElementImpl implemen 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 a532ad897..80634ebb9 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.facade.UMLRTUMLRTPackage; 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 @@ public class UMLRTConnectorImpl extends UMLRTNamedElementImpl implements UMLRTCo 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 @@ public class UMLRTConnectorImpl extends UMLRTNamedElementImpl implements UMLRTCo 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 c74977f6f..9c1caba18 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.Objects; 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.DerivedUnionEObjectEList; 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 @@ public abstract class UMLRTNamedElementImpl extends FacadeObjectImpl implements */ 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 @@ public abstract class UMLRTNamedElementImpl extends FacadeObjectImpl implements 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 46c0215af..9ffcc1332 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.Objects; 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 @@ public class UMLRTPackageImpl extends UMLRTNamedElementImpl implements UMLRTPack 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 @@ public class UMLRTPackageImpl extends UMLRTNamedElementImpl implements UMLRTPack return UMLRTUMLRTPackage.Literals.PACKAGE; } + @Override + protected BasicFacadeAdapter<? extends UMLRTPackageImpl> createFacadeAdapter() { + return new PackageAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -146,7 +271,10 @@ public class UMLRTPackageImpl extends UMLRTNamedElementImpl implements UMLRTPack */ @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 @@ public class UMLRTPackageImpl extends UMLRTNamedElementImpl implements UMLRTPack */ @Override public List<UMLRTCapsule> getCapsules() { - return getFacades(CAPSULE_REFERENCE); + if (capsules == null) { + capsules = (InternalFacadeEList<UMLRTCapsule>) getFacades(CAPSULE_REFERENCE); + } + return capsules; } /** @@ -236,12 +367,16 @@ public class UMLRTPackageImpl extends UMLRTNamedElementImpl implements UMLRTPack */ @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 2ac4a498a..d38bdd7ad 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.function.Predicate; 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.Property; 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 @@ public class UMLRTPortImpl extends UMLRTReplicatedElementImpl implements UMLRTPo */ 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 @@ public class UMLRTPortImpl extends UMLRTReplicatedElementImpl implements UMLRTPo return UMLRTUMLRTPackage.Literals.PORT; } + @Override + protected BasicFacadeAdapter<? extends UMLRTPortImpl> createFacadeAdapter() { + return new PortAdapter<>(this); + } + /** * <!-- begin-user-doc --> * <!-- end-user-doc --> @@ -379,21 +518,7 @@ public class UMLRTPortImpl extends UMLRTReplicatedElementImpl implements UMLRTPo */ @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 f3c43b920..ac3098941 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.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.Protocol; import org.eclipse.papyrusrt.umlrt.profile.UMLRealTime.RTMessageKind; @@ -117,6 +118,7 @@ public class UMLRTProtocolImpl extends UMLRTClassifierImpl implements UMLRTProto 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 @@ public class UMLRTProtocolImpl extends UMLRTClassifierImpl implements UMLRTProto 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 @@ public class UMLRTProtocolImpl extends UMLRTClassifierImpl implements UMLRTProto 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 @@ public class UMLRTProtocolImpl extends UMLRTClassifierImpl implements UMLRTProto 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 @@ public class UMLRTProtocolImpl extends UMLRTClassifierImpl implements UMLRTProto } @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 @@ public class UMLRTProtocolImpl extends UMLRTClassifierImpl implements UMLRTProto 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 0051f4e06..4547937f7 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.Objects; 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.impl.InternalUMLRTElement; 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 @@ public class UMLRTProtocolMessageImpl extends UMLRTNamedElementImpl implements U */ 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 @@ public class UMLRTProtocolMessageImpl extends UMLRTNamedElementImpl implements U 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 @@ public class UMLRTProtocolMessageImpl extends UMLRTNamedElementImpl implements U 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 @@ public class UMLRTProtocolMessageImpl extends UMLRTNamedElementImpl implements U */ @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 d571717af..3044719e7 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 @@ package org.eclipse.papyrusrt.umlrt.uml.internal.facade.impl; 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 @@ public abstract class UMLRTReplicatedElementImpl extends UMLRTNamedElementImpl i */ 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 @@ public abstract class UMLRTReplicatedElementImpl extends UMLRTNamedElementImpl i 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 c3c9179ef..190d0df5e 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 @@ public abstract class FacadeObjectImpl extends MinimalEObjectImpl.Container impl 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 @@ public abstract class FacadeObjectImpl extends MinimalEObjectImpl.Container impl removeAdapter(getTarget()); } - return facade.get(); + return result; } @Override @@ -345,13 +345,13 @@ public abstract class FacadeObjectImpl extends MinimalEObjectImpl.Container impl } 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 @@ public abstract class FacadeObjectImpl extends MinimalEObjectImpl.Container impl 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 18cd9e07d..f16869440 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.emf.ecore.util.Switch; 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.internal.umlext.util.ExtensionResource; 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 @@ public abstract class InheritanceAdapter extends AdapterImpl { 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 @@ public abstract class InheritanceAdapter extends AdapterImpl { } 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 @@ public abstract class InheritanceAdapter extends AdapterImpl { } 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 000000000..b1cb247ed --- /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 000000000..377571700 --- /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 000000000..ce580974e --- /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 000000000..543bc024f --- /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 000000000..046e97f1c --- /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 000000000..af2bbfb28 --- /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 000000000..9e31ed8ea --- /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 80f8876a1..ccb91e213 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 static org.junit.Assert.fail; 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.Set; 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.IDisposable; 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.Namespace; 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 @@ import org.junit.runner.Description; * @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 @@ public class ModelFixture extends TestWatcher { 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 @@ public class ModelFixture extends TestWatcher { 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 @@ public class ModelFixture extends TestWatcher { } }; - 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 @@ public class ModelFixture extends TestWatcher { 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)); + } } |