diff --git a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java index a39a31073..c1a3c0f75 100644 --- a/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java +++ b/plugins/org.eclipse.uml2.uml/src/org/eclipse/uml2/uml/util/UMLUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023 IBM Corporation, Embarcadero Technologies, CEA, Christian W. Damus, EclipseSource and others. + * Copyright (c) 2005, 2023, 2024 IBM Corporation, Embarcadero Technologies, CEA, Christian W. Damus, EclipseSource and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -19,6 +19,7 @@ * Camille Letavernier (EclipseSource) - 544487, 545578 * Camille Letavernier (EclipseSource) - 544487, 545578 * Eike Stepper - 582622 + * Pauline Deville (CEA) - 11 */ package org.eclipse.uml2.uml.util; @@ -27,11 +28,13 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -113,7 +116,6 @@ import org.eclipse.uml2.uml.OpaqueExpression; import org.eclipse.uml2.uml.Operation; import org.eclipse.uml2.uml.OperationOwner; -import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.PackageMerge; import org.eclipse.uml2.uml.Parameter; import org.eclipse.uml2.uml.ParameterDirectionKind; @@ -693,29 +695,25 @@ public static void setStereotypeApplicationStorage(Element element, StereotypeApplicationHelper helper = newStorage != null ? null :StereotypeApplicationHelper .getInstance(outermostPackage); - for (Iterator it = outermostPackage.eAllContents(); it - .hasNext();) { - EObject object = it.next(); - if (object instanceof Element) { - element = (Element) object; + Set stereotypeApplicationsToAdd = new HashSet(); + Set stereotypeApplicationsToClean = new HashSet(); + + manageElementForMigrationToNewStereotypeApplicationStorage(newStorage, oldStorage, helper, stereotypeApplicationsToAdd, stereotypeApplicationsToClean, outermostPackage); - for (EObject stereotypeApplication : element - .getStereotypeApplications()) { - Stereotype stereotype = getStereotype( - stereotypeApplication); + for (Iterator it = outermostPackage.eAllContents(); it.hasNext();) { + EObject object = it.next(); + manageElementForMigrationToNewStereotypeApplicationStorage(newStorage, oldStorage, helper, stereotypeApplicationsToAdd, stereotypeApplicationsToClean, object); + } - if (newStorage != null) { - newStorage.addStereotypeApplication(element, - stereotype, stereotypeApplication); - } else { - helper.addToContainmentList(element, - stereotypeApplication, stereotype); - } + if (newStorage != null) { + for (StereotypeApplicationInformations stereotypeApplicationInfo : stereotypeApplicationsToAdd) { + newStorage.addStereotypeApplication(stereotypeApplicationInfo.element, stereotypeApplicationInfo.stereotype, stereotypeApplicationInfo.stereotypeApplication); + } + } - if (oldStorage != null) { - oldStorage.cleanup(element); - } - } + if (oldStorage != null) { + for (StereotypeApplicationInformations stereotypeApplicationInfo : stereotypeApplicationsToClean) { + oldStorage.cleanup(stereotypeApplicationInfo.element); } } @@ -732,6 +730,73 @@ public static void setStereotypeApplicationStorage(Element element, } } + /** + * The goal of this method is to store in stereotypeApplicationsToAdd and stereotypeApplicationsToClean element that should be + * add of clean according to the given object + * + * @param newStorage + * the new StereotypeApplicationStorage + * @param oldStorage + * the old StereotypeApplicationStorage + * @param helper + * @param stereotypeApplicationsToAdd + * the set of StereotypeApplicationInformations to complete for stereotype application to add + * @param stereotypeApplicationsToClean + * the set of StereotypeApplicationInformations to complete for stereotype application to clean + * @param object + * the optionally stereotyped object + */ + private static void manageElementForMigrationToNewStereotypeApplicationStorage(StereotypeApplicationStorage newStorage, StereotypeApplicationStorage oldStorage, StereotypeApplicationHelper helper, + Set stereotypeApplicationsToAdd, + Set stereotypeApplicationsToClean, EObject object) { + Element element; + if (object instanceof Element) { + element = (Element) object; + + for (EObject stereotypeApplication : element.getStereotypeApplications()) { + Stereotype stereotype = getStereotype(stereotypeApplication); + + if (newStorage != null) { + stereotypeApplicationsToAdd.add(new StereotypeApplicationInformations(element, stereotype, stereotypeApplication)); + } else { + helper.addToContainmentList(element, stereotypeApplication, stereotype); + } + + if (oldStorage != null) { + stereotypeApplicationsToClean.add(new StereotypeApplicationInformations(element, stereotype, stereotypeApplication)); + } + } + } + } + + /** + * Class to be able to easily manipulate stereotype applications informations + */ + private static class StereotypeApplicationInformations { + + /** + * + * Constructor. + * + * @param element + * the stereotyped element + * @param stereotype + * the stereotype applied + * @param stereotypeApplication + * the stereotype application + */ + public StereotypeApplicationInformations(Element element, Stereotype stereotype, EObject stereotypeApplication) { + super(); + this.element = element; + this.stereotype = stereotype; + this.stereotypeApplication = stereotypeApplication; + } + + private Element element; + private Stereotype stereotype; + private EObject stereotypeApplication; + } + /** * A storage and retrieval strategy for stereotype application * {@link EObject objects}. diff --git a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug582622StereotypeApplicationStorageTest.java b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug582622StereotypeApplicationStorageTest.java index 33cffdaf3..e16252072 100644 --- a/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug582622StereotypeApplicationStorageTest.java +++ b/tests/org.eclipse.uml2.uml.tests/src/org/eclipse/uml2/uml/bug/tests/Bug582622StereotypeApplicationStorageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Eike Stepper (Loehne, Germany), CEA, and others.. + * Copyright (c) 2023-2024 Eike Stepper (Loehne, Germany), CEA, and others.. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Pauline Deville (CEA) - 13 */ package org.eclipse.uml2.uml.bug.tests; @@ -53,7 +54,9 @@ public class Bug582622StereotypeApplicationStorageTest private Profile profile; - private Stereotype stereo; + private Stereotype stereoClass; + + private Stereotype stereoPackage; public Bug582622StereotypeApplicationStorageTest() { super(); @@ -143,10 +146,15 @@ protected void setUp() profile.setURI("http://www.eclipse.org/bogus/schema/2013/profile"); res.getContents().add(profile); - Class metaclass = getMetaclass("Class"); - profile.createMetaclassReference(metaclass); - stereo = profile.createOwnedStereotype("test", false); - stereo.createExtension(metaclass, false); + Class metaclassClass = getMetaclass("Class"); + profile.createMetaclassReference(metaclassClass); + stereoClass = profile.createOwnedStereotype("test_Class", false); + stereoClass.createExtension(metaclassClass, false); + + Class metaclassPackage = getMetaclass("Package"); + profile.createMetaclassReference(metaclassPackage); + stereoPackage = profile.createOwnedStereotype("test_Package", false); + stereoPackage.createExtension(metaclassPackage, false); profile.define(); pkg.applyProfile(profile); @@ -190,8 +198,8 @@ public void test_applyAndUnapplyStereotype() { // 2) Apply the stereotype. Verify that the SA is stored in the // "StereotypeApplications" EAnnotation below the element. - EObject application = fixture.applyStereotype(stereo); - assertTrue(fixture.isStereotypeApplied(stereo)); + EObject application = fixture.applyStereotype(stereoClass); + assertTrue(fixture.isStereotypeApplied(stereoClass)); assertURIFragment( "/0/Foo/%http:%2F%2Fwww.eclipse.org%2Fuml2%2FStereotypeApplications%/@contents.0", application); @@ -199,8 +207,8 @@ public void test_applyAndUnapplyStereotype() { // 3) Unapply the stereotype. Verify that the SA is deleted. - fixture.unapplyStereotype(stereo); - assertFalse(fixture.isStereotypeApplied(stereo)); + fixture.unapplyStereotype(stereoClass); + assertFalse(fixture.isStereotypeApplied(stereoClass)); assertURIFragment(null, application); } @@ -219,15 +227,15 @@ public void test_applyAndUnapplyStereotype__TestStorage() { // 2) Apply the stereotype. Verify that the SA is no longer stored in // the resource's contents list. - EObject application = fixture.applyStereotype(stereo); - assertTrue(fixture.isStereotypeApplied(stereo)); + EObject application = fixture.applyStereotype(stereoClass); + assertTrue(fixture.isStereotypeApplied(stereoClass)); assertURIFragment(null, application); assertEquals(2, fixture.eResource().getContents().size()); // 3) Unapply the stereotype. Verify that the SA is deleted. - fixture.unapplyStereotype(stereo); - assertFalse(fixture.isStereotypeApplied(stereo)); + fixture.unapplyStereotype(stereoClass); + assertFalse(fixture.isStereotypeApplied(stereoClass)); assertURIFragment(null, application); } @@ -236,8 +244,8 @@ public void test_migrateStereotypeApplications() { // 1) Apply the stereotype while no special SA Storage // is active. Verify that the SA is stored in the resource contents. - EObject application = fixture.applyStereotype(stereo); - assertTrue(fixture.isStereotypeApplied(stereo)); + EObject application = fixture.applyStereotype(stereoClass); + assertTrue(fixture.isStereotypeApplied(stereoClass)); assertURIFragment("/2", application); assertEquals(3, fixture.eResource().getContents().size()); @@ -251,7 +259,7 @@ public void test_migrateStereotypeApplications() { UMLUtil.setStereotypeApplicationStorage(fixture, ContainedByElement.INSTANCE); - assertTrue(fixture.isStereotypeApplied(stereo)); + assertTrue(fixture.isStereotypeApplied(stereoClass)); assertURIFragment( "/0/Foo/%http:%2F%2Fwww.eclipse.org%2Fuml2%2FStereotypeApplications%/@contents.0", application); @@ -265,7 +273,7 @@ public void test_migrateStereotypeApplications() { // Verify that the SA is stored in the resource contents. UMLUtil.setStereotypeApplicationStorage(fixture, null); - assertTrue(fixture.isStereotypeApplied(stereo)); + assertTrue(fixture.isStereotypeApplied(stereoClass)); assertURIFragment("/2", application); assertEquals(3, fixture.eResource().getContents().size()); @@ -275,14 +283,17 @@ public void test_migrateStereotypeApplications() { } public void test_migrateStereotypeApplications__TestStorage() { - - // 1) Apply the stereotype while no special SA Storage + // 1) Apply stereotypes while no special SA Storage // is active. Verify that the SA is stored in the resource contents. + Element rootPackage = fixture.getOwner(); + assertTrue(rootPackage instanceof Package); + EObject applicationRoot = rootPackage.applyStereotype(stereoPackage); + assertURIFragment("/2", applicationRoot); - EObject application = fixture.applyStereotype(stereo); - assertTrue(fixture.isStereotypeApplied(stereo)); - assertURIFragment("/2", application); - assertEquals(3, fixture.eResource().getContents().size()); + EObject applicationFixture = fixture.applyStereotype(stereoClass); + assertTrue(fixture.isStereotypeApplied(stereoClass)); + assertURIFragment("/3", applicationFixture); + assertEquals(4, fixture.eResource().getContents().size()); StereotypeApplicationStorage storage1 = UMLUtil .getStereotypeApplicationStorage(fixture); @@ -294,8 +305,8 @@ public void test_migrateStereotypeApplications__TestStorage() { StereotypeApplicationStorage testStorage = UMLUtil .setStereotypeApplicationStorageID(fixture, TestStorage.ID); - assertTrue(fixture.isStereotypeApplied(stereo)); - assertURIFragment(null, application); + assertTrue(fixture.isStereotypeApplied(stereoClass)); + assertURIFragment(null, applicationFixture); assertEquals(2, fixture.eResource().getContents().size()); StereotypeApplicationStorage storage2 = UMLUtil @@ -306,9 +317,11 @@ public void test_migrateStereotypeApplications__TestStorage() { // Verify that the SA is stored in the resource contents. UMLUtil.setStereotypeApplicationStorage(fixture, null); - assertTrue(fixture.isStereotypeApplied(stereo)); - assertURIFragment("/2", application); - assertEquals(3, fixture.eResource().getContents().size()); + assertTrue(rootPackage.isStereotypeApplied(stereoPackage)); + assertTrue(fixture.isStereotypeApplied(stereoClass)); + assertURIFragment("/2", applicationRoot); + assertURIFragment("/3", applicationFixture); + assertEquals(4, fixture.eResource().getContents().size()); StereotypeApplicationStorage storage3 = UMLUtil .getStereotypeApplicationStorage(fixture);