Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2021-01-11 22:12:46 +0000
committerPatrick Tessier2021-04-06 07:36:12 +0000
commitd9ca5ad2e9bc05ad4c494dc3b93c18a6a7ae71f8 (patch)
treefe9f48236794e119df38e210faeebdc6f4f6a3d0
parent9e03b102a5f265a4b0af06c5df38e15357ff2d50 (diff)
downloadorg.eclipse.papyrus-d9ca5ad2e9bc05ad4c494dc3b93c18a6a7ae71f8.tar.gz
org.eclipse.papyrus-d9ca5ad2e9bc05ad4c494dc3b93c18a6a7ae71f8.tar.xz
org.eclipse.papyrus-d9ca5ad2e9bc05ad4c494dc3b93c18a6a7ae71f8.zip
Bug 551740: [AF][validation] we must check that all representation are referenced by a viewpoint
- add a custom validation rule to the architecture validation builder to check for references from some viewpoint to a representation kind - requires augmentation of the ArchitectureIndex to look for internal cross-references within the architecture models, not just external cross-references from architecture models to other tooling models - the latter motivated encapsulating some more friendly APIs in the ArchitectureIndex - and also is based on a new reusable InternalCrossReferencer utility - minor fixes to bundle metadata of some test projects files Change-Id: I9b7bf44d22bab442502eee01a11dfdddd3c42f1d Signed-off-by: Christian W. Damus <give.a.damus@gmail.com>
-rw-r--r--plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/InternalCrossReferencer.java151
-rw-r--r--plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.architecture/src/org/eclipse/papyrus/toolsmiths/validation/architecture/internal/checkers/ArchitectureCustomValidator.java51
-rw-r--r--plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/ArchitectureIndex.java275
-rw-r--r--plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/PluginErrorReporter.java27
-rw-r--r--tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/org.eclipse.papyrus.infra.emf.tests.launch83
-rw-r--r--tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/tests/AllTests.java8
-rw-r--r--tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/utils/InternalCrossReferencerTest.java392
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/bug551740-models/BookStore-unusedRepresentationKind.architecture32
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/META-INF/MANIFEST.MF3
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/src/org/eclipse/papyrus/toolsmiths/validation/architecture/classdiagram/internal/commands/CreateInventoryDiagramCommand.java14
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/plugin.properties2
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateBookstoreModelCommand.java14
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateInventoryDiagramCommand.java14
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.classpath7
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.project34
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.settings/org.eclipse.jdt.core.prefs319
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/META-INF/MANIFEST.MF29
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/build.properties20
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/plugin.properties14
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/plugin.xml27
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/resources/UsedBookStore.architecture13
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/src/org/eclipse/papyrus/toolsmiths/validation/architecture/usedbooks/internal/commands/ConvertToUsedBookstoreModelCommand.java27
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/src/org/eclipse/papyrus/toolsmiths/validation/architecture/usedbooks/internal/commands/CreateUsedBookstoreModelCommand.java28
-rw-r--r--tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/src/org/eclipse/papyrus/toolsmiths/validation/architecture/tests/ArchitectureModelBuilderTest.java29
24 files changed, 1527 insertions, 86 deletions
diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/InternalCrossReferencer.java b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/InternalCrossReferencer.java
new file mode 100644
index 00000000000..8eda5d34b49
--- /dev/null
+++ b/plugins/infra/emf/org.eclipse.papyrus.infra.emf/src/org/eclipse/papyrus/infra/emf/utils/InternalCrossReferencer.java
@@ -0,0 +1,151 @@
+/*****************************************************************************
+ * Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.utils;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * <p>
+ * An analogue of the {@link EcoreUtil.ExternalCrossReferencer} that considers only <em>internal</em>
+ * cross-references, between elements of the graphs being searched for cross-references.
+ * </p>
+ * <p>
+ * <strong>Note</strong> that, by design, this class will scan an entire graph of EMF objects
+ * from top to bottom. In environments such as CDO where the content of the graph is not all
+ * loaded in memory at all times and where filling out the graph could be expensive, it may
+ * be advisable at least to derive a customization of this class to reduce its scope or (more
+ * likely) the framework in question has native solutions that are more appropriate and
+ * perhaps more capable.
+ * </p>
+ *
+ * @since 4.1
+ */
+@SuppressWarnings("serial")
+public class InternalCrossReferencer extends EcoreUtil.CrossReferencer {
+
+ /**
+ * Initializes me with the given scope of EMF objects to search for cross-references.
+ * These can be {@link EObject}s, {@link Resource}s, {@link ResourceSet}s, or any mix thereof.
+ *
+ * @param emfObjects
+ * EMF objects to scan for cross-references
+ */
+ protected InternalCrossReferencer(Collection<?> emfObjects) {
+ super(emfObjects);
+ }
+
+ /**
+ * Initializes me with an object whose content tree to scan for cross-references.
+ *
+ * @param eObject
+ * a content tree to scan for cross-references
+ */
+ protected InternalCrossReferencer(EObject eObject) {
+ super(eObject);
+ }
+
+ /**
+ * Initializes me with a resource whose content tree to scan for cross-references.
+ *
+ * @param resource
+ * a resource to scan for cross-references
+ */
+ protected InternalCrossReferencer(Resource resource) {
+ super(resource);
+ }
+
+ /**
+ * Initializes me with a resource set whose content tree to scan for cross-references.
+ *
+ * @param resourceSet
+ * a resource set to scan for cross-references
+ */
+ protected InternalCrossReferencer(ResourceSet resourceSet) {
+ super(resourceSet);
+ }
+
+ @Override
+ protected boolean crossReference(EObject eObject, EReference eReference, EObject crossReferencedEObject) {
+ return EcoreUtil.isAncestor(emfObjects, crossReferencedEObject); // Opposite of ExternalCrossReferencer criterion
+ }
+
+ /**
+ * Compute a map of all cross references that are strictly internal to the given content tree.
+ * The given scope of EMF objects can be {@link EObject}s, {@link Resource}s,
+ * {@link ResourceSet}s, or any mix thereof.
+ *
+ * @param emfObjects
+ * EMF objects to scan for cross-references
+ * @return a map of internal cross-references
+ */
+ public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Collection<?> emfObjects) {
+ return new InternalCrossReferencer(emfObjects).findInternalCrossReferences();
+ }
+
+ /**
+ * Compute a map of all cross references that are strictly internal to the given content tree.
+ *
+ * @param eObject
+ * a content tree to scan for cross-references
+ * @return a map of internal cross-references
+ */
+ public static Map<EObject, Collection<EStructuralFeature.Setting>> find(EObject eObject) {
+ return new InternalCrossReferencer(eObject).findInternalCrossReferences();
+ }
+
+ /**
+ * Compute a map of all cross references that are strictly internal to the given resource.
+ *
+ * @param resource
+ * a resource to scan for cross-references
+ * @return a map of internal cross-references
+ */
+ public static Map<EObject, Collection<EStructuralFeature.Setting>> find(Resource resource) {
+ return new InternalCrossReferencer(resource).findInternalCrossReferences();
+ }
+
+ /**
+ * Compute a map of all cross references that are strictly internal to the given resource set.
+ *
+ * @param eObject
+ * a resource set to scan for cross-references
+ * @return a map of internal cross-references
+ */
+ public static Map<EObject, Collection<EStructuralFeature.Setting>> find(ResourceSet resourceSet) {
+ return new InternalCrossReferencer(resourceSet).findInternalCrossReferences();
+ }
+
+ /**
+ * Compute the internal cross-references.
+ *
+ * @return a map of internal cross-references
+ */
+ protected Map<EObject, Collection<EStructuralFeature.Setting>> findInternalCrossReferences() {
+ crossReference();
+ done();
+
+ return this;
+ }
+
+}
diff --git a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.architecture/src/org/eclipse/papyrus/toolsmiths/validation/architecture/internal/checkers/ArchitectureCustomValidator.java b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.architecture/src/org/eclipse/papyrus/toolsmiths/validation/architecture/internal/checkers/ArchitectureCustomValidator.java
index 70ef53f239c..ecc38ab0763 100644
--- a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.architecture/src/org/eclipse/papyrus/toolsmiths/validation/architecture/internal/checkers/ArchitectureCustomValidator.java
+++ b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.architecture/src/org/eclipse/papyrus/toolsmiths/validation/architecture/internal/checkers/ArchitectureCustomValidator.java
@@ -27,14 +27,19 @@ import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.papyrus.infra.core.architecture.ADElement;
import org.eclipse.papyrus.infra.core.architecture.ArchitectureContext;
+import org.eclipse.papyrus.infra.core.architecture.ArchitecturePackage;
+import org.eclipse.papyrus.infra.core.architecture.ArchitectureViewpoint;
import org.eclipse.papyrus.infra.core.architecture.RepresentationKind;
import org.eclipse.papyrus.infra.types.ElementTypeSetConfiguration;
import org.eclipse.papyrus.infra.types.core.extensionpoints.IElementTypeSetExtensionPoint;
import org.eclipse.papyrus.toolsmiths.validation.architecture.internal.messages.Messages;
import org.eclipse.papyrus.toolsmiths.validation.common.checkers.CustomModelChecker;
+import org.eclipse.papyrus.toolsmiths.validation.common.internal.utils.ArchitectureIndex;
import org.eclipse.pde.core.plugin.IPluginElement;
/**
@@ -54,6 +59,7 @@ public class ArchitectureCustomValidator extends CustomModelChecker.SwitchValida
public void validate(RepresentationKind representation, DiagnosticChain diagnostics, Map<Object, Object> context) {
validateIcon(representation, representation.getGrayedIcon(), diagnostics, context);
+ validateRepresentationKindUsed(representation, diagnostics, context);
}
private void validateIcon(EObject owner, String iconURI, DiagnosticChain diagnostics, Map<Object, Object> context) {
@@ -94,4 +100,49 @@ public class ArchitectureCustomValidator extends CustomModelChecker.SwitchValida
}
}
+ private void validateRepresentationKindUsed(RepresentationKind representation, DiagnosticChain diagnostics, Map<Object, Object> context) {
+ if (!findArchitectureContextReference(representation)) {
+ diagnostics.add(createDiagnostic(Diagnostic.WARNING, representation, format("No viewpoint includes ''{0}'', so it is not accessible.", context, representation)));
+ }
+ }
+
+ /**
+ * Search the registered architecture context models to find any {@link ArchitectureViewpoint viewpoint} that
+ * references the given {@code representation}.
+ *
+ * @param representation
+ * a representation kind
+ * @return whether any viewpoint references it
+ */
+ protected boolean findArchitectureContextReference(RepresentationKind representation) {
+ // The simplest case is a reference within the same architecture model
+ boolean result = !requireCrossReferenceAdapter(representation)
+ .getInverseReferences(representation, ArchitecturePackage.Literals.ARCHITECTURE_VIEWPOINT__REPRESENTATION_KINDS, false).isEmpty();
+
+ if (!result) {
+ // Look for references from other registered architecture models (including from the workspace)
+ result = ArchitectureIndex.getInstance().isReferenced(representation, ArchitecturePackage.Literals.ARCHITECTURE_VIEWPOINT__REPRESENTATION_KINDS);
+ }
+
+ return result;
+ }
+
+ private ECrossReferenceAdapter requireCrossReferenceAdapter(EObject object) {
+ ECrossReferenceAdapter result = ECrossReferenceAdapter.getCrossReferenceAdapter(object);
+
+ if (result == null) {
+ result = new ECrossReferenceAdapter();
+ Resource resource = object.eResource();
+ ResourceSet rset = (resource != null) ? resource.getResourceSet() : null;
+ if (rset != null) {
+ rset.eAdapters().add(result);
+ } else if (resource != null) {
+ resource.eAdapters().add(result);
+ } else {
+ object.eAdapters().add(result);
+ }
+ }
+
+ return result;
+ }
}
diff --git a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/ArchitectureIndex.java b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/ArchitectureIndex.java
index a61cd25d842..8e736b71e3e 100644
--- a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/ArchitectureIndex.java
+++ b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/ArchitectureIndex.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2020 Christian W. Damus, CEA LIST, and others.
+ * Copyright (c) 2020, 2021 Christian W. Damus, CEA LIST, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -16,23 +16,34 @@
package org.eclipse.papyrus.toolsmiths.validation.common.internal.utils;
import java.util.Collection;
+import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
+import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.papyrus.infra.architecture.ArchitectureDomainManager;
import org.eclipse.papyrus.infra.core.architecture.ADElement;
import org.eclipse.papyrus.infra.core.architecture.ArchitectureDomain;
import org.eclipse.papyrus.infra.core.architecture.merged.MergedArchitectureDomain;
import org.eclipse.papyrus.infra.core.utils.JobExecutorService;
+import org.eclipse.papyrus.infra.emf.utils.InternalCrossReferencer;
+import org.eclipse.papyrus.toolsmiths.validation.common.Activator;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimap;
@@ -49,7 +60,9 @@ public class ArchitectureIndex {
private final Executor executor = new JobExecutorService();
- private AtomicReference<CompletableFuture<Multimap<EObject, EStructuralFeature.Setting>>> externalCrossReferences = new AtomicReference<>();
+ private final Map<Mode, Computation<Multimap<EObject, EStructuralFeature.Setting>>> crossReferences = new EnumMap<>(Map.of(
+ Mode.EXTERNAL_CROSS_REFERENCE, new Computation<>(this::computeExternalCrossReferences),
+ Mode.INTERNAL_CROSS_REFERENCE, new Computation<>(this::computeInternalCrossReferences)));
/**
* Not instantiable by clients.
@@ -74,19 +87,22 @@ public class ArchitectureIndex {
* Obtain a calculation of all cross-references from registered architecture models to tooling models
* (and anything else) not contained within one of those architecture models.
*
+ * @param crossReferenceMode
+ * the cross-reference mode to query
* @return the external cross-references of the current architecture domain models
*/
- public Future<Multimap<EObject, EStructuralFeature.Setting>> getExternalCrossReferences() {
- CompletableFuture<Multimap<EObject, EStructuralFeature.Setting>> newResult = new CompletableFuture<>();
- CompletableFuture<Multimap<EObject, EStructuralFeature.Setting>> result = externalCrossReferences.compareAndExchange(null, newResult);
-
- if (result == null) {
- // We made the exchange, so should initiate the computation
- result = newResult;
- result.completeAsync(this::computeExternalCrossReferences, executor);
- }
+ public CompletableFuture<Multimap<EObject, EStructuralFeature.Setting>> getCrossReferences(Mode crossReferenceMode) {
+ return crossReferences.get(crossReferenceMode).get();
+ }
- return result;
+ /**
+ * Obtain a calculation of all cross-references from registered architecture models to tooling models
+ * (and anything else) not contained within one of those architecture models.
+ *
+ * @return the external cross-references of the current architecture domain models
+ */
+ public CompletableFuture<Multimap<EObject, EStructuralFeature.Setting>> getExternalCrossReferences() {
+ return getCrossReferences(Mode.EXTERNAL_CROSS_REFERENCE);
}
private Multimap<EObject, EStructuralFeature.Setting> computeExternalCrossReferences() {
@@ -104,10 +120,241 @@ public class ArchitectureIndex {
}
/**
+ * Obtain a calculation of all cross-references from objects in registered architecture models to other objects
+ * contained within one of those architecture models.
+ *
+ * @return the internal cross-references of the current architecture domain models
+ */
+ public CompletableFuture<Multimap<EObject, EStructuralFeature.Setting>> getInternalCrossReferences() {
+ return getCrossReferences(Mode.INTERNAL_CROSS_REFERENCE);
+ }
+
+ private Multimap<EObject, EStructuralFeature.Setting> computeInternalCrossReferences() {
+ Set<? extends ADElement> architectureDomains = ArchitectureDomainManager.getInstance().getMerger().getDomains().stream()
+ .map(MergedArchitectureDomain::getMergedElements)
+ .flatMap(Collection::stream)
+ .collect(Collectors.toSet());
+
+ ImmutableListMultimap.Builder<EObject, EStructuralFeature.Setting> result = ImmutableListMultimap.builder();
+ for (Map.Entry<EObject, Collection<EStructuralFeature.Setting>> next : InternalCrossReferencer.find(architectureDomains).entrySet()) {
+ result.putAll(next.getKey(), next.getValue());
+ }
+
+ return result.build();
+ }
+
+ /**
* Cancel any pending index calculations; forget all index calculations.
*/
private void domainManagerChanged() {
- Optional.ofNullable(externalCrossReferences.getAndSet(null)).ifPresent(future -> future.cancel(false));
+ crossReferences.values().forEach(Computation::reset);
+ }
+
+ /**
+ * Query whether any object in the given {@code resource} is referenced by some registered <em>architecture model</em>.
+ *
+ * @param crossReferenceMode
+ * the cross-reference mode to query
+ * @param resource
+ * a resource
+ * @return whether it is referenced by a registered architecture model
+ */
+ public boolean isReferenced(Mode crossReferenceMode, Resource resource) {
+ return isReferenced(crossReferenceMode, resource, null);
+ }
+
+ /**
+ * Query whether any object in the given {@code resource} is referenced by some registered <em>architecture model</em>
+ * via the given {@code reference}. Objects cross-referenced by other references are not considered.
+ *
+ * @param crossReferenceMode
+ * the cross-reference mode to query
+ * @param resource
+ * a resource
+ * @param reference
+ * the reference to consider by which objects in the {@code resource} may be referenced
+ * @return whether any object in the {@code resource} is referenced by a registered architecture model via the {@code reference}
+ */
+ public boolean isReferenced(Mode crossReferenceMode, Resource resource, EReference reference) {
+ return Optional.ofNullable(resource).map(Resource::getResourceSet)
+ .map(context -> isReferenced(crossReferenceMode, resource.getURI(), reference, context))
+ .orElse(false);
+ }
+
+ /**
+ * Query whether the given {@code object} is referenced by some registered <em>architecture model</em>.
+ * The cross-reference mode is inferred from the type of {@code object}, which either is an <em>architecture
+ * model</em> element, implying internal cross-reference search, or not, implying external cross-references.
+ *
+ * @param object
+ * a model object
+ * @return whether it is referenced by a registered architecture model
+ */
+ public boolean isReferenced(EObject object) {
+ return isReferenced(object, null);
+ }
+
+ /**
+ * Query whether the given {@code object} is referenced by some registered <em>architecture model</em>
+ * via the given {@code reference}. Objects cross-referenced by other references are not considered.
+ * The cross-reference mode is inferred from the type of {@code object}, which either is an <em>architecture
+ * model</em> element, implying internal cross-reference search, or not, implying external cross-references.
+ *
+ * @param object
+ * a model object
+ * @param reference
+ * the reference to consider by which objects may be referenced
+ * @return whether the {@code object} is referenced by a registered architecture model via the {@code reference}
+ */
+ public boolean isReferenced(EObject object, EReference reference) {
+ return Optional.ofNullable(object).map(EObject::eResource).map(Resource::getResourceSet)
+ .map(context -> isReferenced(inferCrossReferenceMode(object), EcoreUtil.getURI(object), reference, context))
+ .orElse(false);
+ }
+
+ /**
+ * Infer the cross-reference mode to query for an {@code object}. The mode will be inferred as
+ * {@linkplain Mode#INTERNAL_CROSS_REFERENCE internal} if the {@code object} is in an architecture
+ * domain; {@linkplain Mode#EXTERNAL_CROSS_REFERENCE external}, otherwise.
+ *
+ * @param object
+ * an object for which to query cross-references
+ * @return the inferred cross-reference query mode
+ */
+ private static Mode inferCrossReferenceMode(EObject object) {
+ return (object instanceof ADElement)
+ ? Mode.INTERNAL_CROSS_REFERENCE
+ : object != null && object.eContainer() != null
+ ? inferCrossReferenceMode(object.eContainer())
+ : Mode.EXTERNAL_CROSS_REFERENCE;
+ }
+
+ /**
+ * Query whether any registered <em>architecture model</em> has an HREF matching the given {@code uri}.
+ *
+ * @param crossReferenceMode
+ * the cross-reference mode to query
+ * @param uri
+ * an URI, which may be a resource URI or an object URI ({@linkplain URI#hasFragment() with fragment})
+ * @param context
+ * the resource set in which to resolve/convert URIs for stable comparison
+ * @return whether any registered architecture has an HREF matching the given URI
+ */
+ public boolean isReferenced(Mode crossReferenceMode, URI uri, ResourceSet context) {
+ return isReferenced(crossReferenceMode, uri, null, context);
+ }
+
+ /**
+ * Query whether any registered <em>architecture model</em> has an HREF matching the given {@code uri}
+ * in the given {@code reference}. HREFs in other references are not considered.
+ *
+ * @param crossReferenceMode
+ * the cross-reference mode to query
+ * @param uri
+ * an URI, which may be a resource URI or an object URI ({@linkplain URI#hasFragment() with fragment})
+ * @param reference
+ * the reference to consider in looking for HREFs
+ * @param context
+ * the resource set in which to resolve/convert URIs for stable comparison
+ * @return whether any registered architecture has an HREF matching the given URI in the {@code reference}
+ */
+ public boolean isReferenced(Mode crossReferenceMode, URI uri, EReference reference, ResourceSet context) {
+ boolean result = false;
+
+ try {
+ CompletableFuture<Boolean> futureResult = isReferencedAsync(crossReferenceMode, uri, reference, context);
+ result = Boolean.TRUE.equals(futureResult.get());
+ } catch (ExecutionException | InterruptedException e) {
+ // Cannot access the architecture index? Then we didn't find anything
+ Activator.log.error("Error querying Architecture Context models.", e); //$NON-NLS-1$
+ }
+
+ return result;
+ }
+
+ /**
+ * Asynchronously query whether any registered <em>architecture model</em> has an HREF matching the given {@code uri}
+ * in the given {@code reference}. HREFs in other references are not considered.
+ *
+ * @param crossReferenceMode
+ * the cross-reference mode to query
+ * @param uri
+ * an URI, which may be a resource URI or an object URI ({@linkplain URI#hasFragment() with fragment})
+ * @param reference
+ * the reference to consider in looking for HREFs
+ * @param context
+ * the resource set in which to resolve/convert URIs for stable comparison
+ * @return whether any registered architecture has an HREF matching the given URI in the {@code reference}
+ */
+ public CompletableFuture<Boolean> isReferencedAsync(Mode crossReferenceMode, URI uri, EReference reference, ResourceSet context) {
+ URIConverter converter = context.getURIConverter();
+ Function<URI, URI> uriTrimmer = uri.hasFragment() ? Function.identity() : URI::trimFragment;
+ Predicate<Map.Entry<EObject, EStructuralFeature.Setting>> referenceFilter = (reference == null)
+ ? __ -> true
+ : entry -> entry.getValue().getEStructuralFeature() == reference;
+
+ // The architecture models are loaded in their own resource set, so look for our model by URI
+ Predicate<Multimap<EObject, EStructuralFeature.Setting>> isReferenced = xrefs -> xrefs
+ .entries().stream()
+ .filter(referenceFilter)
+ .map(Map.Entry::getKey)
+ .map(EcoreUtil::getURI)
+ .map(uriTrimmer)
+ .map(converter::normalize)
+ .anyMatch(uri::equals);
+
+ return getCrossReferences(crossReferenceMode).thenApply(isReferenced::test);
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * Cross-reference indexing/searching modes.
+ */
+ public static enum Mode {
+ /** Search cross-references from architecture models to other tooling models. */
+ EXTERNAL_CROSS_REFERENCE,
+ /** Search cross-references wihin and between architecture models only. */
+ INTERNAL_CROSS_REFERENCE;
+ }
+
+ /**
+ * A potentially long-running computation that provides for thread-safe initiation
+ * and cancellation/reset to re-compute when inputs change.
+ *
+ * @param <T>
+ * the type of the computation
+ */
+ private final class Computation<T> implements Supplier<CompletableFuture<T>> {
+ private final AtomicReference<CompletableFuture<T>> computation = new AtomicReference<>();
+ private final Supplier<T> computer;
+
+ Computation(Supplier<T> computer) {
+ super();
+
+ this.computer = computer;
+ }
+
+ @Override
+ public CompletableFuture<T> get() {
+ CompletableFuture<T> newResult = new CompletableFuture<>();
+ CompletableFuture<T> result = computation.compareAndExchange(null, newResult);
+
+ if (result == null) {
+ // We made the exchange, so should initiate the computation
+ result = newResult;
+ result.completeAsync(computer, executor);
+ }
+
+ return result;
+ }
+
+ void reset() {
+ Optional.ofNullable(computation.getAndSet(null)).ifPresent(future -> future.cancel(false));
+ }
+
}
}
diff --git a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/PluginErrorReporter.java b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/PluginErrorReporter.java
index c5f1ed2b5ef..f252318c96a 100644
--- a/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/PluginErrorReporter.java
+++ b/plugins/toolsmiths/validation/org.eclipse.papyrus.toolsmiths.validation.common/src/org/eclipse/papyrus/toolsmiths/validation/common/internal/utils/PluginErrorReporter.java
@@ -10,7 +10,7 @@
*
* Contributors:
* Remi Schnekenburger (EclipseSource) - Initial API and implementation
- * Christian W. Damus - bugs 569357, 570097
+ * Christian W. Damus - bugs 569357, 570097, 551740
*
*****************************************************************************/
package org.eclipse.papyrus.toolsmiths.validation.common.internal.utils;
@@ -23,7 +23,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import org.eclipse.core.resources.IFile;
@@ -32,10 +31,7 @@ import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.URIMappingRegistryImpl;
-import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.osgi.util.NLS;
import org.eclipse.papyrus.toolsmiths.validation.common.Activator;
import org.eclipse.papyrus.toolsmiths.validation.common.checkers.IPluginChecker2;
@@ -482,29 +478,10 @@ public class PluginErrorReporter<T extends EObject> extends ManifestErrorReporte
* @return whether a cross-reference is found in any architecture context
*/
protected boolean findArchitectureContextReference() {
- boolean result = false;
-
// We do not need extensions on the set registration point if some architecture context includes the set
- URIConverter converter = getModel().eResource().getResourceSet().getURIConverter();
- URI myModelURI = converter.normalize(EcoreUtil.getURI(getModel()));
-
- try {
- Multimap<EObject, EStructuralFeature.Setting> xrefs = ArchitectureIndex.getInstance().getExternalCrossReferences().get();
-
- // The architecture models are loaded in their own resource set, so look for our model by URI
- result = xrefs.keySet().stream()
- .map(EcoreUtil::getURI)
- .map(converter::normalize)
- .filter(myModelURI::equals)
- .anyMatch(myModelURI::equals);
- } catch (ExecutionException | InterruptedException e) {
- // Cannot access the architecture index? Then we didn't find anything
- Activator.log.error("Error querying Architecture Context models.", e); //$NON-NLS-1$
+ return ArchitectureIndex.getInstance().isReferenced(getModel());
}
- return result;
- }
-
//
// Nested types
//
diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/org.eclipse.papyrus.infra.emf.tests.launch b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/org.eclipse.papyrus.infra.emf.tests.launch
index 4b263025c93..45e124b8170 100644
--- a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/org.eclipse.papyrus.infra.emf.tests.launch
+++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/org.eclipse.papyrus.infra.emf.tests.launch
@@ -1,44 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.pde.ui.JunitLaunchConfig">
-<booleanAttribute key="append.args" value="true"/>
-<stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
-<booleanAttribute key="askclear" value="false"/>
-<booleanAttribute key="automaticAdd" value="true"/>
-<booleanAttribute key="automaticValidate" value="false"/>
-<stringAttribute key="bootstrap" value=""/>
-<stringAttribute key="checked" value="[NONE]"/>
-<booleanAttribute key="clearConfig" value="true"/>
-<booleanAttribute key="clearws" value="true"/>
-<booleanAttribute key="clearwslog" value="false"/>
-<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
-<booleanAttribute key="default" value="true"/>
-<booleanAttribute key="includeOptional" value="true"/>
-<stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
-<listEntry value="/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/tests/AllTests.java"/>
-</listAttribute>
-<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
-<listEntry value="1"/>
-</listAttribute>
-<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
-<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
-<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
-<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
-<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
-<stringAttribute key="org.eclipse.jdt.launching.JAVA_COMMAND" value="java"/>
-<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
-<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.papyrus.infra.emf.tests.AllTests"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.papyrus.infra.emf.tests"/>
-<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms768m -Xmx1024m &#10;-Doomph.setup.skip=true -Doomph.setup.questionnaire.skip=true"/>
-<stringAttribute key="pde.version" value="3.3"/>
-<stringAttribute key="product" value="org.eclipse.platform.ide"/>
-<booleanAttribute key="run_in_ui_thread" value="true"/>
-<booleanAttribute key="show_selected_only" value="false"/>
-<booleanAttribute key="tracing" value="false"/>
-<booleanAttribute key="useCustomFeatures" value="false"/>
-<booleanAttribute key="useDefaultConfig" value="true"/>
-<booleanAttribute key="useDefaultConfigArea" value="false"/>
-<booleanAttribute key="useProduct" value="false"/>
+ <booleanAttribute key="append.args" value="true"/>
+ <stringAttribute key="application" value="org.eclipse.pde.junit.runtime.coretestapplication"/>
+ <booleanAttribute key="askclear" value="false"/>
+ <booleanAttribute key="automaticAdd" value="true"/>
+ <booleanAttribute key="automaticValidate" value="false"/>
+ <stringAttribute key="bootstrap" value=""/>
+ <stringAttribute key="checked" value="[NONE]"/>
+ <booleanAttribute key="clearConfig" value="true"/>
+ <booleanAttribute key="clearws" value="true"/>
+ <booleanAttribute key="clearwslog" value="false"/>
+ <stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/pde-junit"/>
+ <booleanAttribute key="default" value="true"/>
+ <booleanAttribute key="includeOptional" value="true"/>
+ <stringAttribute key="location" value="${workspace_loc}/../junit-workspace"/>
+ <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+ <listEntry value="/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/tests/AllTests.java"/>
+ </listAttribute>
+ <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+ <listEntry value="1"/>
+ </listAttribute>
+ <stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
+ <booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+ <stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+ <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit4"/>
+ <booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/>
+ <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
+ <stringAttribute key="org.eclipse.jdt.launching.JAVA_COMMAND" value="java"/>
+ <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.papyrus.infra.emf.tests.AllTests"/>
+ <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
+ <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.papyrus.infra.emf.tests"/>
+ <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
+ <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms768m -Xmx1024m &#10;-Doomph.setup.skip=true -Doomph.setup.questionnaire.skip=true"/>
+ <stringAttribute key="pde.version" value="3.3"/>
+ <stringAttribute key="product" value="org.eclipse.platform.ide"/>
+ <booleanAttribute key="run_in_ui_thread" value="true"/>
+ <booleanAttribute key="show_selected_only" value="false"/>
+ <booleanAttribute key="tracing" value="false"/>
+ <booleanAttribute key="useCustomFeatures" value="false"/>
+ <booleanAttribute key="useDefaultConfig" value="true"/>
+ <booleanAttribute key="useDefaultConfigArea" value="false"/>
+ <booleanAttribute key="useProduct" value="false"/>
</launchConfiguration>
diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/tests/AllTests.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/tests/AllTests.java
index 8337589b7a7..7ae6b79ebed 100644
--- a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/tests/AllTests.java
+++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/tests/AllTests.java
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2014, 2016 CEA, Christian W. Damus, and others.
- *
+ * Copyright (c) 2014, 2021 CEA, 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 2.0
* which accompanies this distribution, and is available at
@@ -10,7 +10,7 @@
*
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
- * Christian W. Damus - bugs 399859, 465416, 485220, 496299
+ * Christian W. Damus - bugs 399859, 465416, 485220, 496299, 551740
*
*/
package org.eclipse.papyrus.infra.emf.tests;
@@ -21,6 +21,7 @@ import org.eclipse.papyrus.infra.emf.resource.CrossReferenceIndexTest;
import org.eclipse.papyrus.infra.emf.resource.ShardResourceHelperTest;
import org.eclipse.papyrus.infra.emf.resource.ShardResourceLocatorTest;
import org.eclipse.papyrus.infra.emf.resource.index.WorkspaceModelIndexTest;
+import org.eclipse.papyrus.infra.emf.utils.InternalCrossReferencerTest;
import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceTest;
import org.eclipse.papyrus.infra.types.core.registries.ElementTypeSetConfigurationRegistry;
import org.eclipse.papyrus.junit.framework.classification.ClassificationSuite;
@@ -43,6 +44,7 @@ import org.junit.runners.Suite.SuiteClasses;
// oep.infra.emf.edit.domain
PapyrusTransactionalEditingDomainTest.class,
// oep.infra.emf.utils
+ InternalCrossReferencerTest.class,
ServiceUtilsForResourceTest.class,
// oep.infra.emf.resource
ShardResourceHelperTest.class, ShardResourceLocatorTest.class, CrossReferenceIndexTest.class,
diff --git a/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/utils/InternalCrossReferencerTest.java b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/utils/InternalCrossReferencerTest.java
new file mode 100644
index 00000000000..c6c764c1976
--- /dev/null
+++ b/tests/junit/plugins/infra/emf/org.eclipse.papyrus.infra.emf.tests/tests/org/eclipse/papyrus/infra/emf/utils/InternalCrossReferencerTest.java
@@ -0,0 +1,392 @@
+/*****************************************************************************
+ * Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.emf.utils;
+
+import static org.hamcrest.CoreMatchers.anything;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test cases for the {@link InternalCrossReferencer} class.
+ */
+@RunWith(Parameterized.class)
+public class InternalCrossReferencerTest {
+
+ private EObject referent;
+ private EObject referrer;
+ private EReference reference;
+
+ private Object scope;
+ private boolean expectedToFind;
+
+ /**
+ * Initializes me.
+ *
+ * @param label
+ * the test label (unused)
+ * @param referent
+ * the object for which to find an internal reference to it
+ * @param referrer
+ * the object that has a reference to the {@code referent}
+ * @param reference
+ * the feature by which the {@link referrer} references the {@code referent}
+ * @param scope
+ * the scope to search
+ * @param expectedToFind
+ * whether the search is expected to find the <em>internal</em> cross-reference or not
+ */
+ public InternalCrossReferencerTest(String label, EObject referent, EObject referrer, EReference reference, Object scope, boolean expectedToFind) {
+ super();
+
+ this.referent = referent;
+ this.referrer = referrer;
+ this.reference = reference;
+ this.scope = scope;
+ this.expectedToFind = expectedToFind;
+ }
+
+ /**
+ * Verify that an internal cross-reference search in the test's scope finds
+ * or does not find the internal cross-reference as indicated. In any case it is
+ * asserted that the cross-reference <em>does actually exist</em> even if only as
+ * an <em>external</em> reference.
+ */
+ @Test
+ public void testFind() {
+ checkExternalCrossReference();
+
+ Map<EObject, Collection<EStructuralFeature.Setting>> crossReferences;
+ if (scope instanceof EObject) {
+ crossReferences = InternalCrossReferencer.find((EObject) scope);
+ } else if (scope instanceof Resource) {
+ crossReferences = InternalCrossReferencer.find((Resource) scope);
+ } else if (scope instanceof ResourceSet) {
+ crossReferences = InternalCrossReferencer.find((ResourceSet) scope);
+ } else if (scope instanceof Collection<?>) {
+ crossReferences = InternalCrossReferencer.find((Collection<?>) scope);
+ } else {
+ fail("Unsupported search scope type: " + scope);
+ return; // Unreachable
+ }
+
+ if (expectedToFind) {
+ verify(crossReferences);
+ } else {
+ verifyNot(crossReferences);
+ }
+ }
+
+ //
+ // Test configurations
+ //
+
+ @Parameters(name = "{0}")
+ public static Iterable<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ // Test that a cross-reference is found when both objects are in a forest of EObjects
+ new Fixture().label("collection (internal)").scoped(collection(false)).expectToFind(true).toParameters(),
+ // Test that a cross-reference is ignored when only the referring object object is in the search scope
+ new Fixture().label("collection (external)").scoped(collection(true)).expectToFind(false).toParameters(),
+ // Test that a cross-reference is found when both objects are in a single tree of EObjects
+ new Fixture().label("single tree (internal)").scoped(container(false)).expectToFind(true).toParameters(),
+ // Test that a cross-reference is ignored when only the referring object object is in the search scope
+ new Fixture().label("single tree (external)").scoped(container(true)).expectToFind(false).toParameters(),
+ // Test that a cross-reference is found when both objects are in a single resource
+ new Fixture().label("resource (internal)").scoped(resource(false)).expectToFind(true).toParameters(),
+ // Test that a cross-reference is ignored when the objects are in separate resources but only the
+ // referring object's resource is in the search scope
+ new Fixture().label("separate resources (external)").scoped(resource(true)).expectToFind(false).toParameters(),
+ // Test that a cross-reference is found when the objects are in separate resources and both
+ // resources are in the search scope
+ new Fixture().label("separate resources (internal)").scoped(resources(true)).expectToFind(true).toParameters(),
+ // Test that a cross-reference is found when both objects are in a single resource set
+ new Fixture().label("resource set (internal)").scoped(resourceSet(true)).expectToFind(true).toParameters(),
+ // Test that a cross-reference is ignored when the objects are in separate resource sets and only the
+ // referring object's resource set is in the search scope
+ new Fixture().label("separate resource sets (external)").scoped(resourceSets(true)).expectToFind(false).toParameters(),
+ // Test that a cross-reference is found when the objects are in separate resource sets and both
+ // resource sets are in the search scope
+ new Fixture().label("separate resource sets (internal)").scoped(resourceSets(false)).expectToFind(true).toParameters(),
+ });
+ }
+
+ /**
+ * Scope function that puts objects into some collection. The result is the collection as scope.
+ *
+ * @param referrerOnly
+ * whether to put only the referring object into the collection
+ */
+ static BiFunction<EObject, EObject, Collection<? super EObject>> collection(boolean referrerOnly) {
+ return aggregate(BasicEList::new, Function.identity(), !referrerOnly, true);
+ }
+
+ /**
+ * Scope function that puts objects into some container object. The result is the container object as scope.
+ *
+ * @param referrerOnly
+ * whether to put only the referring object into the container
+ */
+ static BiFunction<EObject, EObject, ? extends EObject> container(boolean referrerOnly) {
+ return aggregate(EcoreFactory.eINSTANCE::createEAnnotation, EAnnotation::getContents, !referrerOnly, true);
+ }
+
+ /**
+ * Scope function that puts objects into resources.
+ *
+ * @param separate
+ * whether the objects are put each into their own resource, or otherwise into the same resource.
+ * In the former case, the scope will be the resource containing the referring object
+ */
+ static BiFunction<EObject, EObject, Resource> resource(boolean separate) {
+ // The referrer is always in the first resource in the set
+ return resources(separate).andThen(c -> c.get(0));
+ }
+
+ /**
+ * Scope function that puts objects into resources.
+ *
+ * @param separate
+ * whether the objects are put each into their own resource
+ */
+ static BiFunction<EObject, EObject, List<Resource>> resources(boolean separate) {
+ // The referrer is always in the first resource in the set
+ return resourceSet(separate).andThen(ResourceSet::getResources);
+ }
+
+ /**
+ * Scope function that puts every object into a single resource set.
+ *
+ * @param separateResources
+ * whether the objects are put each into their own resource
+ */
+ static BiFunction<EObject, EObject, ResourceSet> resourceSet(boolean separateResources) {
+ BiConsumer<ResourceSet, ? super EObject> acceptor = (rset, e) -> {
+ Resource res;
+ if (separateResources || rset.getResources().isEmpty()) {
+ res = new ResourceImpl();
+ rset.getResources().add(0, res); // Insert so that the referrer is always in the first resource
+ } else {
+ res = rset.getResources().get(0);
+ }
+ res.getContents().add(e);
+ };
+
+ return generic(ResourceSetImpl::new, acceptor, acceptor, true, true);
+ }
+
+ /**
+ * Scope function that puts every object into its own resource set.
+ *
+ * @param referrerOnly
+ * whether the scope includes only the referring object's resource set
+ */
+ static BiFunction<EObject, EObject, ?> resourceSets(boolean referrerOnly) {
+ Function<EObject, ResourceSet> rsetFactory = e -> {
+ ResourceSet result = new ResourceSetImpl();
+ Resource res = new ResourceImpl();
+ result.getResources().add(res);
+ res.getContents().add(e);
+ return result;
+ };
+
+ // The referrer is always in the first resource set
+ BiConsumer<List<ResourceSet>, EObject> acceptor = (rsets, e) -> rsets.add(0, rsetFactory.apply(e));
+
+ BiFunction<EObject, EObject, List<ResourceSet>> result = generic(BasicEList::new, acceptor, acceptor, true, true);
+ return referrerOnly ? result.andThen(rset -> rset.get(0)) : result;
+ }
+
+ /** Scope function that aggregates the model objects in a collection or other kind of container. */
+ static <T> BiFunction<EObject, EObject, T> aggregate(Supplier<T> factory, Function<? super T, ? extends Collection<? super EObject>> contentsFunction,
+ boolean include1, boolean include2) {
+
+ BiConsumer<T, ? super EObject> acceptor = (r, e) -> contentsFunction.apply(r).add(e);
+ return generic(factory, acceptor, acceptor, include1, include2);
+ }
+
+ /** Generic scope function. */
+ static <T> BiFunction<EObject, EObject, T> generic(Supplier<T> factory,
+ BiConsumer<? super T, ? super EObject> acceptor1, BiConsumer<? super T, ? super EObject> acceptor2,
+ boolean include1, boolean include2) {
+
+ return (e1, e2) -> {
+ T result = factory.get();
+ if (include1) {
+ acceptor1.accept(result, e1);
+ }
+ if (include2) {
+ acceptor2.accept(result, e2);
+ }
+ return result;
+ };
+ }
+
+ //
+ // Test framework
+ //
+
+ /**
+ * Verify that the map of cross references contains the reference from our fixture
+ * 'referrer' element to our fixture 'referent' element.
+ *
+ * @param crossReferences
+ * the map of cross-references found in the test scenario
+ */
+ void verify(Map<EObject, Collection<EStructuralFeature.Setting>> crossReferences) {
+ Collection<EStructuralFeature.Setting> settings = crossReferences.get(referent);
+ assertThat("EClass references not found by cross-referencer", settings, notNullValue());
+
+ EStructuralFeature.Setting setting = settings.stream()
+ .filter(s -> s.getEObject() == referrer && s.getEStructuralFeature() == reference)
+ .findFirst()
+ .orElse(null);
+ assertThat("Reference from EReference to EClass not found by cross-referencer", setting, notNullValue());
+ }
+
+ /**
+ * Verify that the map of cross references <em>does not</em> contain the reference from our fixture
+ * 'referrer' element to our fixture 'referent' element, despite that the scan encountered the
+ * 'referrer', because the reference in the test scenario was an <em>external</em> reference.
+ *
+ * @param crossReferences
+ * the map of cross-references found in the test scenario
+ */
+ void verifyNot(Map<EObject, Collection<EStructuralFeature.Setting>> crossReferences) {
+ Collection<EStructuralFeature.Setting> settings = crossReferences.get(referent);
+ if (settings == null) {
+ // Good, that's what we want
+ return;
+ }
+
+ EStructuralFeature.Setting setting = settings.stream()
+ .filter(s -> s.getEObject() == referrer && s.getEStructuralFeature() == reference)
+ .findFirst()
+ .orElse(null);
+ assertThat("External reference from EReference to EClass found by internal cross-referencer", setting, nullValue());
+ }
+
+ /**
+ * Verify that the map of cross references contains the reference from our fixture
+ * 'referrer' element to our fixture 'referent' element, even if only as an
+ * <em>external</em> reference (not internal).
+ *
+ * @param crossReferences
+ * the collection of cross-references found in the test scenario
+ */
+ void checkExternalCrossReference() {
+ Collection<?> scope = this.scope instanceof Collection ? (Collection<?>) this.scope : Set.of(this.scope);
+ Collection<EStructuralFeature.Setting> crossReferences = EcoreUtil.UsageCrossReferencer.find(referent, scope);
+ assertThat("Bad test setup: the target object is not referenced at all in the scenario", crossReferences, hasItem(anything()));
+
+ EStructuralFeature.Setting setting = crossReferences.stream()
+ .filter(s -> s.getEObject() == referrer && s.getEStructuralFeature() == reference)
+ .findFirst()
+ .orElse(null);
+ assertThat("Bad test setup: the target object is not referenced by the fixture", setting, notNullValue());
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A factory of fixtures on which to operate the tests.
+ */
+ private static final class Fixture {
+ final EPackage package1 = EcoreFactory.eINSTANCE.createEPackage();
+ final EPackage package2 = EcoreFactory.eINSTANCE.createEPackage();
+ // An object for which the tests seek references to it. It is in 'package1'
+ final EClass referent = EcoreFactory.eINSTANCE.createEClass();
+ final EClass referencingClass = EcoreFactory.eINSTANCE.createEClass();
+ // An object having a reference to the 'referent' that tests seek. It is in 'package2'
+ final EReference referrer = EcoreFactory.eINSTANCE.createEReference();
+
+ private String label;
+ private Object scope;
+ private boolean expectedToFind;
+
+ {
+ package1.getEClassifiers().add(referent);
+ package2.getEClassifiers().add(referencingClass);
+ referencingClass.getEStructuralFeatures().add(referrer);
+ referrer.setEType(referent);
+ }
+
+ /** Set the test label to display in the JUnit report. */
+ Fixture label(String label) {
+ this.label = label;
+ return this;
+ }
+
+ /**
+ * Set the scope function that determines how the packages containing (first) the referenced object and
+ * (second) the referencing object are organized relative to one another and which of them are or are
+ * not in the search scope. The result is the scope on which the cross-reference search is performed
+ * and it must be either an {@link EObject}, a {@link Resource}, a {@link ResourceSet}, or a collection
+ * of any of these types.
+ */
+ Fixture scoped(BiFunction<? super EPackage, ? super EPackage, ?> scopeFunction) {
+ scope = scopeFunction.apply(package1, package2);
+ expectedToFind = true;
+ return this;
+ }
+
+ /** Set whether the test should expect to find the cross reference, or not. */
+ Fixture expectToFind(boolean expect) {
+ this.expectedToFind = expect;
+ return this;
+ }
+
+ /** Generate the test parameters. */
+ Object[] toParameters() {
+ return new Object[] { label, referent, referrer, EcorePackage.Literals.ETYPED_ELEMENT__ETYPE, scope, expectedToFind };
+ }
+
+ }
+
+}
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/bug551740-models/BookStore-unusedRepresentationKind.architecture b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/bug551740-models/BookStore-unusedRepresentationKind.architecture
new file mode 100644
index 00000000000..6264a671da5
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/bug551740-models/BookStore-unusedRepresentationKind.architecture
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<architecture:ArchitectureDomain xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:architecture="http://www.eclipse.org/papyrus/infra/core/architecture" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:elementtypesconfigurations="http://www.eclipse.org/papyrus/infra/elementtypesconfigurations/1.2" xmlns:gmfdiagrepresentation="http://www.eclipse.org/papyrus/infra/gmfdiag/representation" xmlns:paletteconfiguration="http://www.eclipse.org/papyrus/diagram/paletteconfiguration/0.8" xmlns:representation="http://www.eclipse.org/papyrus/infra/core/architecture/representation" xmi:id="_W0vj0FG2EeuXzM4mqVly4g" id="org.eclipse.papyrus.toolsmiths.validation.architecture.example.bookstore" name="BookStore" description="Example architecture domain for testing: a book store modeling language." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/bookstore.png">
+ <stakeholders xmi:type="architecture:Stakeholder" xmi:id="_zYz54FG5EeuXzM4mqVly4g" id="org.eclipse.papyrus.toolsmiths.validation.architecture.example.bookvendor" name="Book Vendor" description="A seeler of books, in a bookstore." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/book_vendor.png" concerns="_95r3oFG5EeuXzM4mqVly4g"/>
+ <concerns xmi:type="architecture:Concern" xmi:id="_95r3oFG5EeuXzM4mqVly4g" id="org.eclipse.papyrus.toolsmiths.validation.architecture.example.bookselling" name="Book Selling" description="The concern of selling books, in a book store." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/bookstore.png"/>
+ <contexts xmi:type="architecture:ArchitectureDescriptionLanguage" xmi:id="_Ty_tQFG6EeuXzM4mqVly4g" id="org.eclipse.papyrus.toolsmiths.validation.architecture.example.bookstorelang" name="BookStore" icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/bookstore.png" defaultViewpoints="_fnEJgFHAEeuwtJo37XL9OQ" extensionPrefix="bookstore" creationCommandClass="org.eclipse.papyrus.toolsmiths.validation.architecture.example.internal.commands.CreateBookstoreModelCommand">
+ <viewpoints xmi:type="architecture:ArchitectureViewpoint" xmi:id="_fnEJgFHAEeuwtJo37XL9OQ" id="org.eclipse.papyrus.toolsmiths.validation.architecture.example.bookstoremanagement" name="BookStore Management" description="The viewpoint of the book store manager who needs to track inventory." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/book_vendor.png" concerns="_95r3oFG5EeuXzM4mqVly4g"/>
+ <elementTypes xmi:type="elementtypesconfigurations:ElementTypeSetConfiguration" href="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/resources/BookStore.elementtypesconfigurations#_c0DGsGBhEemoFuWBTUmJOQ"/>
+ <representationKinds xmi:type="gmfdiagrepresentation:PapyrusDiagram" xmi:id="_u1T1UFHAEeuwtJo37XL9OQ" id="org.eclipse.papyrus.toolsmiths.validation.architecture.example.inventory" name="InventoryDiagram" description="Book store inventory diagram." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/bookstore.png" concerns="_95r3oFG5EeuXzM4mqVly4g" grayedIcon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/bookstore_d.png" implementationID="org.eclipse.papyrus.toolsmiths.validation.architecture.example.InventoryDiagram" creationCommandClass="org.eclipse.papyrus.toolsmiths.validation.architecture.example.internal.commands.CreateInventoryDiagramCommand">
+ <modelRules xmi:type="representation:ModelRule" xmi:id="__8BXQFHDEeuwtJo37XL9OQ" permit="true" elementMultiplicity="1" multiplicity="-1">
+ <element xmi:type="ecore:EClass" href="http://www.eclipse.org/uml2/5.0.0/UML#//Package"/>
+ <stereotypes xmi:type="ecore:EClass" href="http://www.eclipse.org/Papyrus/test/toolsmiths/architecturebuilder/BookStore#_e24cBFG7EeuXzM4mqVly4g"/>
+ </modelRules>
+ <owningRules xmi:type="representation:OwningRule" xmi:id="_GnAokFHEEeuwtJo37XL9OQ" permit="true" multiplicity="-1">
+ <element xmi:type="ecore:EClass" href="http://www.eclipse.org/uml2/5.0.0/UML#//Package"/>
+ <stereotypes xmi:type="ecore:EClass" href="http://www.eclipse.org/Papyrus/test/toolsmiths/architecturebuilder/BookStore#_e24cBFG7EeuXzM4mqVly4g"/>
+ </owningRules>
+ <childRules xmi:type="gmfdiagrepresentation:ChildRule" xmi:id="_LyaWcFHEEeuwtJo37XL9OQ" permit="true">
+ <element xmi:type="ecore:EClass" href="http://www.eclipse.org/uml2/5.0.0/UML#//Class"/>
+ <stereotypes xmi:type="ecore:EClass" href="http://www.eclipse.org/Papyrus/test/toolsmiths/architecturebuilder/BookStore#_e24cDFG7EeuXzM4mqVly4g"/>
+ <origin xmi:type="ecore:EClass" href="http://www.eclipse.org/uml2/5.0.0/UML#//Package"/>
+ </childRules>
+ <childRules xmi:type="gmfdiagrepresentation:ChildRule" xmi:id="_TjwL0FHEEeuwtJo37XL9OQ" permit="true">
+ <element xmi:type="ecore:EClass" href="http://www.eclipse.org/uml2/5.0.0/UML#//Class"/>
+ <stereotypes xmi:type="ecore:EClass" href="http://www.eclipse.org/Papyrus/test/toolsmiths/architecturebuilder/BookStore#_e24cCFG7EeuXzM4mqVly4g"/>
+ <origin xmi:type="ecore:EClass" href="http://www.eclipse.org/uml2/5.0.0/UML#//Package"/>
+ </childRules>
+ <palettes xmi:type="paletteconfiguration:PaletteConfiguration" href="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/resources/BookStore.paletteconfiguration#/"/>
+ </representationKinds>
+ <metamodel xmi:type="ecore:EPackage" href="http://www.eclipse.org/uml2/5.0.0/UML#/"/>
+ <profiles xmi:type="ecore:EPackage" href="http://www.eclipse.org/Papyrus/test/toolsmiths/architecturebuilder/BookStore#_e24cAVG7EeuXzM4mqVly4g"/>
+ </contexts>
+</architecture:ArchitectureDomain>
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/META-INF/MANIFEST.MF b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/META-INF/MANIFEST.MF
index eb7642c6bed..8f0eead4885 100644
--- a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/META-INF/MANIFEST.MF
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/META-INF/MANIFEST.MF
@@ -4,7 +4,6 @@ Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram;singleton:=true
Bundle-Version: 2.0.0.qualifier
Bundle-ClassPath: .
-Bundle-Activator: org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram.internal.commands.Activator
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.18.0,4.0.0)",
@@ -26,5 +25,5 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.18.0,4.0.0)",
org.eclipse.papyrus.uml.diagram.clazz;bundle-version="[4.0.0,5.0.0)",
org.eclipse.papyrus.infra.gmfdiag.paletteconfiguration;bundle-version="[5.0.0,6.0.0)"
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Automatic-Module-Name: org.eclipse.papyrus.toolsmiths.validation.elementtypes.example
+Automatic-Module-Name: org.eclipse.papyrus.toolsmiths.validation.elementtypes.classdiagram
Bundle-ActivationPolicy: lazy
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/src/org/eclipse/papyrus/toolsmiths/validation/architecture/classdiagram/internal/commands/CreateInventoryDiagramCommand.java b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/src/org/eclipse/papyrus/toolsmiths/validation/architecture/classdiagram/internal/commands/CreateInventoryDiagramCommand.java
index 57b19aa4feb..2bfd7829811 100644
--- a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/src/org/eclipse/papyrus/toolsmiths/validation/architecture/classdiagram/internal/commands/CreateInventoryDiagramCommand.java
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram/src/org/eclipse/papyrus/toolsmiths/validation/architecture/classdiagram/internal/commands/CreateInventoryDiagramCommand.java
@@ -1,3 +1,17 @@
+/*****************************************************************************
+ * Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
package org.eclipse.papyrus.toolsmiths.validation.architecture.classdiagram.internal.commands;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/plugin.properties b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/plugin.properties
index b690acc685f..b1ebbd16a33 100644
--- a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/plugin.properties
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/plugin.properties
@@ -10,5 +10,5 @@
# Contributors:
# Christian W. Damus - Initial API and implementation
-pluginName = Architecture Plug-in Validation Example Bundle for Testing
+pluginName = Architecture Plug-in Validation Example Bundle (Book Store) for Testing
providerName = Eclipse Modeling Project
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateBookstoreModelCommand.java b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateBookstoreModelCommand.java
index 55b64d93698..ba19859a0ab 100644
--- a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateBookstoreModelCommand.java
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateBookstoreModelCommand.java
@@ -1,3 +1,17 @@
+/*****************************************************************************
+ * Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
package org.eclipse.papyrus.toolsmiths.validation.architecture.example.internal.commands;
import org.eclipse.emf.ecore.EObject;
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateInventoryDiagramCommand.java b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateInventoryDiagramCommand.java
index e21f6e17b38..7b92bb785f8 100644
--- a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateInventoryDiagramCommand.java
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.example/src/org/eclipse/papyrus/toolsmiths/validation/architecture/example/internal/commands/CreateInventoryDiagramCommand.java
@@ -1,3 +1,17 @@
+/*****************************************************************************
+ * Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
package org.eclipse.papyrus.toolsmiths.validation.architecture.example.internal.commands;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.classpath b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.classpath
new file mode 100644
index 00000000000..e801ebfb468
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.project b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.project
new file mode 100644
index 00000000000..e1475ae444f
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.papyrus.plugin.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.papyrus.plugin.nature</nature>
+ </natures>
+</projectDescription>
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.settings/org.eclipse.jdt.core.prefs b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..037f04a07c2
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,319 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=11
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=11
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=260
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=false
+org.eclipse.jdt.core.formatter.join_wrapped_lines=false
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=260
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=5
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/META-INF/MANIFEST.MF b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..3d37eccee32
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/META-INF/MANIFEST.MF
@@ -0,0 +1,29 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-ClassPath: .
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.18.0,4.0.0)",
+ org.eclipse.papyrus.infra.architecture;bundle-version="[3.0.0,4.0.0)",
+ org.eclipse.papyrus.infra.gmfdiag.commands;bundle-version="[4.0.0,5.0.0)",
+ org.eclipse.papyrus.infra.gmfdiag.common;bundle-version="[4.0.0,5.0.0)",
+ org.eclipse.papyrus.infra.core;bundle-version="[4.0.0,5.0.0)",
+ org.eclipse.emf.ecore;bundle-version="[2.23.0,3.0.0)",
+ org.eclipse.gmf.runtime.notation;bundle-version="[1.10.0,2.0.0)",
+ org.eclipse.gmf.runtime.common.core;bundle-version="[1.7.0,2.0.0)",
+ org.eclipse.papyrus.infra.viewpoints.policy;bundle-version="[4.0.0,5.0.0)",
+ org.eclipse.gmf.runtime.diagram.core;bundle-version="[1.7.0,2.0.0)",
+ org.eclipse.papyrus.infra.types;bundle-version="[5.0.0,6.0.0)",
+ org.eclipse.papyrus.infra.types.core;bundle-version="[5.0.0,6.0.0)",
+ org.eclipse.uml2.uml;bundle-version="[5.5.0,6.0.0)",
+ org.eclipse.uml2.uml.resources;bundle-version="[5.5.0,6.0.0)",
+ org.eclipse.papyrus.uml.service.types;bundle-version="[5.0.0,6.0.0)",
+ org.eclipse.papyrus.uml.diagram.common;bundle-version="[4.0.0,5.0.0)",
+ org.eclipse.papyrus.infra.gmfdiag.paletteconfiguration;bundle-version="[5.0.0,6.0.0)",
+ org.eclipse.papyrus.toolsmiths.validation.architecture.example;bundle-version="[2.0.0,3.0.0)"
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Automatic-Module-Name: org.eclipse.papyrus.toolsmiths.validation.elementtypes.usedbooks
+Bundle-ActivationPolicy: lazy
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/build.properties b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/build.properties
new file mode 100644
index 00000000000..6309226d771
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/build.properties
@@ -0,0 +1,20 @@
+# Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# Christian W. Damus - Initial API and implementation
+
+bin.includes = .,\
+ META-INF/,\
+ plugin.xml,\
+ plugin.properties,\
+ resources/
+jars.compile.order = .
+source.. = src
+output.. = bin/
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/plugin.properties b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/plugin.properties
new file mode 100644
index 00000000000..ac47d6f5e85
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/plugin.properties
@@ -0,0 +1,14 @@
+# Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License 2.0
+# which accompanies this distribution, and is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+#
+# Contributors:
+# Christian W. Damus - Initial API and implementation
+
+pluginName = Architecture Plug-in Validation Example Bundle (Used Books) for Testing
+providerName = Eclipse Modeling Project
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/plugin.xml b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/plugin.xml
new file mode 100644
index 00000000000..6b7e2de2269
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/plugin.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+
+<!--
+ Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License 2.0
+ which accompanies this distribution, and is available at
+ https://www.eclipse.org/legal/epl-2.0/
+
+ SPDX-License-Identifier: EPL-2.0
+
+ Contributors:
+ Christian W. Damus - Initial API and implementation
+-->
+
+<plugin>
+
+ <extension
+ point="org.eclipse.papyrus.infra.architecture.models">
+ <model
+ path="resources/UsedBookStore.architecture">
+ </model>
+ </extension>
+
+</plugin>
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/resources/UsedBookStore.architecture b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/resources/UsedBookStore.architecture
new file mode 100644
index 00000000000..a6d97f1b716
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/resources/UsedBookStore.architecture
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<architecture:ArchitectureDomain xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:architecture="http://www.eclipse.org/papyrus/infra/core/architecture" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:elementtypesconfigurations="http://www.eclipse.org/papyrus/infra/elementtypesconfigurations/1.2" xmlns:gmfdiagrepresentation="http://www.eclipse.org/papyrus/infra/gmfdiag/representation" xmi:id="_W0vj0FG2EeuXzM4mqVly4g" id="org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks.bookstore" name="UsedBookStore" description="Example architecture domain for testing: a used book store modeling language." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/bookstore.png">
+ <stakeholders xmi:type="architecture:Stakeholder" xmi:id="_zYz54FG5EeuXzM4mqVly4g" id="org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks.bookvendor" name="Used Book Vendor" description="A seeler of books, in a bookstore." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architectureexample/icons/full/obj16/book_vendor.png" concerns="_95r3oFG5EeuXzM4mqVly4g"/>
+ <concerns xmi:type="architecture:Concern" xmi:id="_95r3oFG5EeuXzM4mqVly4g" id="org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks.bookselling" name="Used Book Selling" description="The concern of selling used books, in a used book store." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/bookstore.png"/>
+ <contexts xmi:type="architecture:ArchitectureDescriptionLanguage" xmi:id="_Ty_tQFG6EeuXzM4mqVly4g" id="org.eclipse.papyrus.toolsmiths.validation.architecture.example.bookstorelang" name="BookStore" icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/bookstore.png" defaultViewpoints="_fnEJgFHAEeuwtJo37XL9OQ" extensionPrefix="bookstore" creationCommandClass="org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks.internal.commands.CreateUsedBookstoreModelCommand" conversionCommandClass="org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks.internal.commands.ConvertToUsedBookstoreModelCommand">
+ <viewpoints xmi:type="architecture:ArchitectureViewpoint" xmi:id="_fnEJgFHAEeuwtJo37XL9OQ" id="org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks.bookstoremanagement" name="Used BookStore Management" description="The viewpoint of the used book store manager who needs to track inventory." icon="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/icons/full/obj16/book_vendor.png" concerns="_95r3oFG5EeuXzM4mqVly4g">
+ <representationKinds xmi:type="gmfdiagrepresentation:PapyrusDiagram" href="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/resources/BookStore.architecture#_u1T1UFHAEeuwtJo37XL9OQ"/>
+ </viewpoints>
+ <elementTypes xmi:type="elementtypesconfigurations:ElementTypeSetConfiguration" href="platform:/plugin/org.eclipse.papyrus.toolsmiths.validation.architecture.example/resources/BookStore.elementtypesconfigurations#_c0DGsGBhEemoFuWBTUmJOQ"/>
+ <metamodel xmi:type="ecore:EPackage" href="http://www.eclipse.org/uml2/5.0.0/UML#/"/>
+ <profiles xmi:type="ecore:EPackage" href="http://www.eclipse.org/Papyrus/test/toolsmiths/architecturebuilder/BookStore#_e24cAVG7EeuXzM4mqVly4g"/>
+ </contexts>
+</architecture:ArchitectureDomain>
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/src/org/eclipse/papyrus/toolsmiths/validation/architecture/usedbooks/internal/commands/ConvertToUsedBookstoreModelCommand.java b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/src/org/eclipse/papyrus/toolsmiths/validation/architecture/usedbooks/internal/commands/ConvertToUsedBookstoreModelCommand.java
new file mode 100644
index 00000000000..735f5a1c4cb
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/src/org/eclipse/papyrus/toolsmiths/validation/architecture/usedbooks/internal/commands/ConvertToUsedBookstoreModelCommand.java
@@ -0,0 +1,27 @@
+/*****************************************************************************
+ * Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks.internal.commands;
+
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.uml.diagram.common.commands.AbstractModelConversionCommand;
+
+public class ConvertToUsedBookstoreModelCommand extends AbstractModelConversionCommand {
+
+ @Override
+ public void doConvertModel(ModelSet modelSet) {
+ // Convert the book store to a used book store
+ }
+
+}
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/src/org/eclipse/papyrus/toolsmiths/validation/architecture/usedbooks/internal/commands/CreateUsedBookstoreModelCommand.java b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/src/org/eclipse/papyrus/toolsmiths/validation/architecture/usedbooks/internal/commands/CreateUsedBookstoreModelCommand.java
new file mode 100644
index 00000000000..9911df1266d
--- /dev/null
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/resources/org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks/src/org/eclipse/papyrus/toolsmiths/validation/architecture/usedbooks/internal/commands/CreateUsedBookstoreModelCommand.java
@@ -0,0 +1,28 @@
+/*****************************************************************************
+ * Copyright (c) 2021 Christian W. Damus, CEA LIST, and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks.internal.commands;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.uml.diagram.common.commands.ModelCreationCommandBase;
+import org.eclipse.uml2.uml.UMLFactory;
+
+public class CreateUsedBookstoreModelCommand extends ModelCreationCommandBase {
+
+ @Override
+ protected EObject createRootElement() {
+ return UMLFactory.eINSTANCE.createModel();
+ }
+
+}
diff --git a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/src/org/eclipse/papyrus/toolsmiths/validation/architecture/tests/ArchitectureModelBuilderTest.java b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/src/org/eclipse/papyrus/toolsmiths/validation/architecture/tests/ArchitectureModelBuilderTest.java
index 2d1a33af896..19397046e25 100644
--- a/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/src/org/eclipse/papyrus/toolsmiths/validation/architecture/tests/ArchitectureModelBuilderTest.java
+++ b/tests/junit/plugins/toolsmiths/org.eclipse.papyrus.toolsmiths.validation.architecture.tests/src/org/eclipse/papyrus/toolsmiths/validation/architecture/tests/ArchitectureModelBuilderTest.java
@@ -162,6 +162,35 @@ public class ArchitectureModelBuilderTest extends AbstractPapyrusTest {
assertThat(modelMarkers, not(hasItem(isMarkerMessage(containsString("is registered to a different context"))))); //$NON-NLS-1$
}
+
+ /**
+ * Test the reporting of an unused representation kind (not referenced by any viewpoint).
+ *
+ * @see <a href="http://eclip.se/551740">bug 551740</a>
+ */
+ @Test
+ @OverlayFile(value = "bug551740-models/BookStore-unusedRepresentationKind.architecture", path = "resources/BookStore.architecture")
+ public void unusedRepresentationKind() {
+ final List<IMarker> modelMarkers = fixture.getMarkers("resources/BookStore.architecture"); //$NON-NLS-1$
+
+ assertThat(modelMarkers, hasItem(both(isMarkerSeverity(IMarker.SEVERITY_WARNING)).and(isMarkerMessage(containsString("No viewpoint includes"))))); //$NON-NLS-1$
+ }
+
+ /**
+ * Test that a representation kind is not unused if a viewpoint in some other registered architecture model references it.
+ *
+ * @see <a href="http://eclip.se/551740">bug 551740</a>
+ */
+ @Test
+ @OverlayFile(value = "bug551740-models/BookStore-unusedRepresentationKind.architecture", path = "resources/BookStore.architecture")
+ // Import the Used Book Store architecture model project that references the representation kind in its viewpoint
+ @AuxProject("org.eclipse.papyrus.toolsmiths.validation.architecture.usedbooks")
+ public void representationKindReferenced() {
+ final List<IMarker> modelMarkers = fixture.getMarkers("resources/BookStore.architecture"); //$NON-NLS-1$
+
+ assertThat(modelMarkers, not(hasItem(isMarkerMessage(containsString("No viewpoint includes"))))); //$NON-NLS-1$
+ }
+
}
}

Back to the top