Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Fleck2016-06-21 03:28:08 -0400
committerGerrit Code Review @ Eclipse.org2016-06-27 11:17:57 -0400
commit0a4fa8933935a3160633e4122eb26a14a0c4aa35 (patch)
tree75133884b80a14a6c9456eddc24e293368569757
parent4c1f28e71861ba3c933a6ca4d46d7c90644bb878 (diff)
downloadorg.eclipse.papyrus-0a4fa8933935a3160633e4122eb26a14a0c4aa35.tar.gz
org.eclipse.papyrus-0a4fa8933935a3160633e4122eb26a14a0c4aa35.tar.xz
org.eclipse.papyrus-0a4fa8933935a3160633e4122eb26a14a0c4aa35.zip
Bug 496307: [Profile Migration] Restrictive package pattern matching
- Add ProfileNamespaceURIPatterns to split namespace URIs into a versionless, identifying namespace URI and the version information. A namespace URI is matched by a given Regex pattern. The versionless namespace URI is a concatenation of all parts of the matches that are not in groups. The version information is a formatted string consisting of the parts matched through the groups in the pattern and therefore may be spread across the URI. The format of the resulting version string can be customized using a dedicated MessageFormat. - Add extension point for profile namespace URI patterns. - Add pattern registry that is initialized with extension points. - Add usage of profile namespace URI patterns when comparing URIs in the zombie stereotypes descriptor, if there is no perfect equality. If no registered pattern handles the URIs, the previous behavior is used as default. - Bump plugin version to 1.2.1 Includes tests for the pattern matching and splitting. Includes tests to test reported behavior and the improved behavior in the zombie stereotypes descriptor. Change-Id: I5f7744c2a19bb20ea2572247f6d47f948504f7b4 Signed-off-by: Martin Fleck <mfleck@eclipsesource.com>
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF3
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml1
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/pom.xml2
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/schema/profileNamespaceURIPattern.exsd173
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java26
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPattern.java160
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternComparison.java116
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternMatchResult.java231
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternRegistry.java235
-rw-r--r--tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/META-INF/MANIFEST.MF1
-rw-r--r--tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/plugin.xml7
-rw-r--r--tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/resources/regression/bug496307/model.uml27
-rw-r--r--tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeRepairRegressionTest.java146
-rw-r--r--tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternTest.java545
-rw-r--r--tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/tests/AllTests.java5
15 files changed, 1656 insertions, 22 deletions
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF
index 82a6f36772f..7b725191468 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF
@@ -3,6 +3,7 @@ Export-Package: org.eclipse.papyrus.uml.modelrepair,
org.eclipse.papyrus.uml.modelrepair.handler,
org.eclipse.papyrus.uml.modelrepair.internal.participants;x-internal:=true,
org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;x-friends:="org.eclipse.papyrus.migration.rsa",
+ org.eclipse.papyrus.uml.modelrepair.internal.uripattern,
org.eclipse.papyrus.uml.modelrepair.internal.validation;x-internal:=true,
org.eclipse.papyrus.uml.modelrepair.service,
org.eclipse.papyrus.uml.modelrepair.ui,
@@ -15,7 +16,7 @@ Require-Bundle: org.eclipse.papyrus.uml.extensionpoints;bundle-version="[1.2.0,2
org.eclipse.uml2.uml.edit;bundle-version="[5.1.0,6.0.0)"
Bundle-Vendor: Eclipse Modeling Project
Bundle-ActivationPolicy: lazy
-Bundle-Version: 1.2.0.qualifier
+Bundle-Version: 1.2.1.qualifier
Bundle-Name: Model Repair
Bundle-Activator: org.eclipse.papyrus.uml.modelrepair.Activator
Bundle-ManifestVersion: 2
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml
index aa3de8549fe..139bc9c5224 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml
@@ -2,6 +2,7 @@
<?eclipse version="3.4"?>
<plugin>
<extension-point id="org.eclipse.papyrus.uml.modelrepair.profileSwitchPreconditions" name="Profile Switch Preconditions" schema="schema/profileSwitchPreconditions.exsd"/>
+ <extension-point id="org.eclipse.papyrus.uml.modelrepair.profileNamespaceURIPattern" name="Profile Namespace URI Pattern" schema="schema/profileNamespaceURIPattern.exsd"/>
<extension
point="org.eclipse.ui.menus">
<menuContribution
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/pom.xml b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/pom.xml
index c5fe2b7f076..a844c7378ce 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/pom.xml
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/pom.xml
@@ -7,6 +7,6 @@
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>org.eclipse.papyrus.uml.modelrepair</artifactId>
- <version>1.2.0-SNAPSHOT</version>
+ <version>1.2.1-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/schema/profileNamespaceURIPattern.exsd b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/schema/profileNamespaceURIPattern.exsd
new file mode 100644
index 00000000000..031ed27ce8b
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/schema/profileNamespaceURIPattern.exsd
@@ -0,0 +1,173 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.papyrus.uml.modelrepair" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.papyrus.uml.modelrepair" id="profileNamespaceURIPattern" name="Profile Namespace URI Pattern"/>
+ </appinfo>
+ <documentation>
+ This extension point is for supporting the profile migration mechanism in Papyrus.
+It provides a regex pattern that identifies the namespace URIs of a profile and enables to extract version information from the URI through pattern groups.
+During the migration, only the namespace URIs minus the version information is used to identify profiles.
+Even if no version information is encoded in the URI, profile providers may use this extension point to enable the automatic migration of their profiles within Papyrus.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence minOccurs="1" maxOccurs="unbounded">
+ <element ref="profileNamespaceURIPattern"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="profileNamespaceURIPattern">
+ <complexType>
+ <attribute name="uriPattern" type="string" use="required">
+ <annotation>
+ <documentation>
+ Regex pattern identifying profile namespace URIs during the profile migration. Groups in the pattern are used to extract versioning information.
+Backslashes (&apos;\&apos;) should not be escaped.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="versionFormat" type="string">
+ <annotation>
+ <documentation>
+ MessageFormat string to produce the versioning string from the groups extracted by the uriPattern. Indices in the format correspond to the indices of the groups matched by the pattern, e.g., {0} refers to group zero holding the entire matched namespace URI and {1} refers to the first matched group. If no format is provided, a comma-separated version string is produced.
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 1.2.1
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ &lt;p&gt;&lt;strong&gt;Namespace URI Matching&lt;/strong&gt;&lt;/p&gt;
+&lt;pre class=&quot;Example&quot;&gt;
+&lt;span class=&quot;code SchemaTag&quot;&gt;&amp;lt;extension point=&lt;/span&gt;&lt;span class=&quot;code SchemaCstring&quot;&gt;&quot;org.eclipse.papyrus.uml.modelrepair.profileNamespaceURIPattern&quot;&lt;/span&gt;&lt;span class=&quot;code SchemaTag&quot;&gt;&amp;gt;&lt;/span&gt;
+ &lt;span class=&quot;code SchemaTag&quot;&gt;&amp;lt;profileNamespaceURIPattern&lt;/span&gt; &lt;span class=&quot;code SchemaTag&quot;&gt;uriPattern=&lt;/span&gt;&lt;span class=&quot;code SchemaCstring&quot;&gt;&quot;^http://www\.eclipse\.org/my/profile/version/([^/]+)/Language/([^/]+)/.*$&quot;&lt;/span&gt; &lt;span class=&quot;code SchemaTag&quot;&gt;/&amp;gt;&lt;/span&gt;
+&lt;span class=&quot;code SchemaTag&quot;&gt;&amp;lt;/extension&amp;gt;&lt;/span&gt;
+&lt;/pre&gt;
+
+&lt;p&gt;Input URI A: http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageA&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;Matched Namespace URI: &quot;http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageA&quot;&lt;/li&gt;
+ &lt;li&gt;Versionless Namespace URI: &quot;http://www.eclipse.org/my/profile/version//Language//PackageA&quot;&lt;/li&gt;
+ &lt;li&gt;Version: &quot;7,7.0.1&quot; (default format)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;Input URI B: http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageB&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;Matched Namespace URI: &quot;http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageA&quot;&lt;/li&gt;
+ &lt;li&gt;Versionless Namespace URI: &quot;http://www.eclipse.org/my/profile/version//Language//PackageB&quot;&lt;/li&gt;
+ &lt;li&gt;Version: &quot;7,7.0.1&quot; (default format)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;Input URI C: http://www.eclipse.org/my/profile/version/6/Language/6.0/PackageB&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;Matched Namespace URI: &quot;http://www.eclipse.org/my/profile/version/6/Language/6.0/PackageB&quot;&lt;/li&gt;
+ &lt;li&gt;Versionless Namespace URI: &quot;http://www.eclipse.org/my/profile/version//Language//PackageB&quot;&lt;/li&gt;
+ &lt;li&gt;Version: &quot;6,6.0&quot; (default format)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;During the migration, input B and C are treated as the same profile, just with a different version, whereas input A is considered as a different profile.&lt;/p&gt;
+
+&lt;p&gt;&lt;strong&gt;Version Formatting&lt;/strong&gt;&lt;/p&gt;
+&lt;pre class=&quot;Example&quot;&gt;
+&lt;span class=&quot;code SchemaTag&quot;&gt;&amp;lt;profileNamespaceURIPattern ... &lt;/span&gt;&lt;span class=&quot;code SchemaTag&quot;&gt;versionFormat=&lt;/span&gt;&lt;span class=&quot;code SchemaCstring&quot;&gt;&quot;-{1}-&quot;&lt;/span&gt;&lt;span class=&quot;code SchemaTag&quot;&gt;/&amp;gt;&lt;/span&gt;
+&lt;/pre&gt;
+
+&lt;p&gt;Input URI A: http://www.eclipse.org/my/profile/version/7/Language/PackageA&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;Version: &quot;-7-&quot;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;pre class=&quot;Example&quot;&gt;
+&lt;span class=&quot;code SchemaTag&quot;&gt;&amp;lt;profileNamespaceURIPattern ... &lt;/span&gt;&lt;span class=&quot;code SchemaTag&quot;&gt;versionFormat=&lt;/span&gt;&lt;span class=&quot;code SchemaCstring&quot;&gt;&quot;{1} - {2}&quot;&lt;/span&gt;&lt;span class=&quot;code SchemaTag&quot;&gt;/&amp;gt;&lt;/span&gt;
+&lt;/pre&gt;
+
+&lt;p&gt;Input URI A: http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageA&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;Version: &quot;7 - 7.0.1&quot;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;pre class=&quot;Example&quot;&gt;
+&lt;span class=&quot;code SchemaTag&quot;&gt;&amp;lt;profileNamespaceURIPattern ... &lt;/span&gt;&lt;span class=&quot;code SchemaTag&quot;&gt;versionFormat=&lt;/span&gt;&lt;span class=&quot;code SchemaCstring&quot;&gt;&quot;{0} | {1}&quot;&lt;/span&gt;&lt;span class=&quot;code SchemaTag&quot;&gt;/&amp;gt;&lt;/span&gt;
+&lt;/pre&gt;
+
+&lt;p&gt;Input URI A: http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageA&lt;/p&gt;
+&lt;ul&gt;
+ &lt;li&gt;Version: &quot;http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageA | 7&quot;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;Special index zero conforms to group zero of the pattern match, which is the entire matched namespace URI.&lt;/p&gt;
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ An internal registry (ProfileNamespaceURIPatternRegistry) is used to control the registering and unregistering of the profile namespace URI patterns.
+This registry is initialized with all extension points, but a programatical removal of provided patterns is possible.
+ </documentation>
+ </annotation>
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2016 EclipseSource and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java
index 1cc14a00c2c..fd764104127 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015 CEA, Christian W. Damus, and others.
+ * Copyright (c) 2014, 2016 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 v1.0
@@ -9,8 +9,9 @@
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
* Christian W. Damus - bug 399859
- * Christian W. Damus - bug 451338
+ * Christian W. Damus - bug 451338
* Christian W. Damus - bug 436666
+ * Martin Fleck - bug 496307
*
*/
package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
@@ -41,6 +42,8 @@ import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.papyrus.infra.core.utils.AdapterUtils;
import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
import org.eclipse.papyrus.uml.modelrepair.internal.participants.StereotypesUtil;
+import org.eclipse.papyrus.uml.modelrepair.internal.uripattern.ProfileNamespaceURIPatternComparison;
+import org.eclipse.papyrus.uml.modelrepair.internal.uripattern.ProfileNamespaceURIPatternRegistry;
import org.eclipse.papyrus.uml.tools.helper.IProfileApplicationDelegate;
import org.eclipse.papyrus.uml.tools.helper.ProfileApplicationDelegateRegistry;
import org.eclipse.uml2.uml.Element;
@@ -53,6 +56,7 @@ import org.eclipse.uml2.uml.util.UMLUtil;
import com.google.common.base.Function;
import com.google.common.base.Objects;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@@ -178,7 +182,7 @@ public class ZombieStereotypesDescriptor {
* <li>adapts to {@link EPackage} to provide the EMF schema that is unresolved or otherwise broken</li>
* <li>may possibly adapt to {@link IStereotypeOrphanGroup} representing stereotype applications from a broken schema that are not repairable by profile migration and so are treated separately with a distinct set of available actions
* </ul>
- *
+ *
* @return the zombie schemas that are detected
*/
public Collection<? extends IAdaptable> getZombieSchemas() {
@@ -308,7 +312,7 @@ public class ZombieStereotypesDescriptor {
/**
* Obtains a repair action of the specified {@code kind} for a broken {@code schema}, if it is available.
- *
+ *
* @param schema
* a schema to repair
* @param kind
@@ -454,9 +458,20 @@ public class ZombieStereotypesDescriptor {
result = schema1 == schema2;
if (!result && (schema1 != null)) { // Implies that schema2 != null, also
- result = Objects.equal(schema1.getNsURI(), schema2.getNsURI());
+ String schema1uri = schema1.getNsURI();
+ String schema2uri = schema2.getNsURI();
+ result = Objects.equal(schema1uri, schema2uri);
if (!result) {
+ // No perfect equality, try to use provided profile package patterns
+
+ // Try to find find a pattern comparison that matches both URIs
+ Optional<ProfileNamespaceURIPatternComparison> comparison = ProfileNamespaceURIPatternRegistry.INSTANCE.tryFindComparison(schema1uri, schema2uri);
+ if (comparison.isPresent()) {
+ return comparison.get().isEqualVersionlessNamespaceURI();
+ }
+
+ // No pattern found that handles the URIs
// Maybe one is a proxy whose URI is the schema-location of the other (being a demand-created package)
URI uri1 = guessURI(schema1);
URI uri2 = guessURI(schema2);
@@ -479,6 +494,7 @@ public class ZombieStereotypesDescriptor {
}
return result;
+
}
static URI guessURI(EPackage schema) {
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPattern.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPattern.java
new file mode 100644
index 00000000000..4805e64d123
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPattern.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Martin Fleck - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.uml.modelrepair.internal.uripattern;
+
+import java.text.MessageFormat;
+import java.util.regex.Pattern;
+
+/**
+ * A profile namespace URI pattern consists of a Regex pattern and an optional version format.
+ * The {@link Pattern} can split profile namespace URIs into versionless namespace URIs which can be used as identification and and the version part.
+ * The version format allows for individual formatting of the extracted version information and needs to conform to the {@link MessageFormat}.
+ *
+ * @author Martin Fleck <mfleck@eclipsesource.com>
+ */
+public class ProfileNamespaceURIPattern {
+
+ /** Regex pattern to split the URI into the profile-identifying part and the versioning part. */
+ private final Pattern pattern;
+
+ /** Message format to format the version parts extracted from the namespace URI */
+ private final MessageFormat versionFormat;
+
+ /**
+ * Creates a new profile namespace URI pattern with the given namespace URI pattern.
+ * The URI pattern is a Regex that can split namespace URIs into the profile-identifying part (without version) and the versioning part.
+ * This constructor uses the default versioning formatting producing a comma-separated version string.
+ *
+ * @param pattern
+ * pattern used to split the namespace URI
+ */
+ public ProfileNamespaceURIPattern(final String pattern) {
+ this(pattern, null);
+ }
+
+ /**
+ * Creates a new profile namespace URI pattern with the given namespace URI pattern and the provided version format.
+ * The URI pattern is a Regex that can split namespace URIs into the profile-identifying part (without version) and the versioning part.
+ * The version format allows for individual formatting of the extracted version information and needs to conform to the {@link MessageFormat}.
+ * Indices in the format correspond to the indices of the groups matched by the pattern, e.g., {0} refers to group zero holding the entire pattern and {1} refers to the first matched group.
+ *
+ * @param pattern
+ * Regex pattern
+ * @param versionFormat
+ * format for the versioning part of the matched namespace URI
+ * @see Pattern
+ * @see MessageFormat
+ */
+ public ProfileNamespaceURIPattern(final String pattern, final String versionFormat) {
+ this.pattern = Pattern.compile(pattern);
+ if (versionFormat != null) {
+ this.versionFormat = new MessageFormat(versionFormat);
+ } else {
+ this.versionFormat = null;
+ }
+ }
+
+ /**
+ * Returns the Regex pattern that can split namespace URIs into the profile-identifying part and the versioning part.
+ *
+ * @return the Regex pattern
+ */
+ public Pattern getRegexPattern() {
+ return pattern;
+ }
+
+ /**
+ * Returns the format that is used to create the {@link ProfileNamespaceURIPatternMatchResult#getVersion() version} string from the groups
+ * of the {@link #getRegexPattern() namespace URI pattern}. If no such format was given, this method returns null.
+ *
+ * @return the versionFormat or null if no such format was given
+ */
+ public MessageFormat getVersionFormat() {
+ return versionFormat;
+ }
+
+
+ /**
+ * Compares the two given URIs based on how they {@link ProfileNamespaceURIPatternMatchResult match} this pattern.
+ * Only if both URIs match the pattern, a {@link ProfileNamespaceURIPatternComparison#isValid() valid} comparison result is returned.
+ *
+ * @param lhsUri
+ * left-hand side URI for the comparison
+ * @param rhsUri
+ * right-hand side URI for the comparison
+ * @return a non-null comparison result, which may or may not be valid
+ */
+ public ProfileNamespaceURIPatternComparison compare(final String lhsUri, final String rhsUri) {
+ final ProfileNamespaceURIPatternMatchResult lhsPattern = match(lhsUri);
+ if (lhsPattern.hasMatched()) {
+ final ProfileNamespaceURIPatternMatchResult rhsPattern = match(rhsUri);
+ if (rhsPattern.hasMatched()) {
+ // both uris match
+ return new ProfileNamespaceURIPatternComparison(lhsPattern, rhsPattern);
+ }
+ }
+ // none or only one uri matches
+ return ProfileNamespaceURIPatternComparison.INVALID;
+ }
+
+ /**
+ * Matches the given uri with this namespace URI pattern.
+ *
+ * @param uri
+ * uri to match
+ * @return a non-null match result, which may or may not {@link ProfileNamespaceURIPatternMatchResult#hasMatched() have matched}.
+ */
+ public ProfileNamespaceURIPatternMatchResult match(final String uri) {
+ if (uri == null) {
+ return ProfileNamespaceURIPatternMatchResult.NO_MATCH;
+ }
+ return new ProfileNamespaceURIPatternMatchResult(pattern.matcher(uri), versionFormat);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((pattern == null) ? 0 : pattern.pattern().hashCode());
+ result = prime * result + ((versionFormat == null) ? 0 : versionFormat.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ProfileNamespaceURIPattern other = (ProfileNamespaceURIPattern) obj;
+ if (pattern == null) {
+ if (other.pattern != null) {
+ return false;
+ }
+ } else if (!pattern.pattern().equals(other.pattern.pattern())) {
+ return false;
+ }
+ if (versionFormat == null) {
+ if (other.versionFormat != null) {
+ return false;
+ }
+ } else if (!versionFormat.equals(other.versionFormat)) {
+ return false;
+ }
+ return true;
+ }
+}
+
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternComparison.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternComparison.java
new file mode 100644
index 00000000000..b7531a30553
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternComparison.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Martin Fleck - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.uml.modelrepair.internal.uripattern;
+
+/**
+ * This convenience class providing comparison methods for two {@link ProfileNamespaceURIPatternMatchResult}es.
+ *
+ * @author Martin Fleck <mfleck@eclipsesource.com>
+ */
+public class ProfileNamespaceURIPatternComparison {
+
+ /** Constant representing an invalid comparison */
+ public static final ProfileNamespaceURIPatternComparison INVALID = new ProfileNamespaceURIPatternComparison(
+ ProfileNamespaceURIPatternMatchResult.NO_MATCH, ProfileNamespaceURIPatternMatchResult.NO_MATCH);
+
+ /** Left-hand side pattern match of the comparison */
+ private final ProfileNamespaceURIPatternMatchResult lhsPatternMatch;
+
+ /** Right-hand side pattern match of the comparison */
+ private final ProfileNamespaceURIPatternMatchResult rhsPatternMatch;
+
+ /**
+ * Creates a new comparison based on the given two matches.
+ * The resulting comparison is only valid if both matches have actually matched.
+ * All comparisons on an invalid comparison yield false as return value.
+ *
+ * @param lhsPatternMatch
+ * first match
+ * @param rhsPatternMatch
+ * second match
+ * @see ProfileNamespaceURIPattern
+ * @see ProfileNamespaceURIPatternRegistry
+ */
+ public ProfileNamespaceURIPatternComparison(final ProfileNamespaceURIPatternMatchResult lhsPatternMatch,
+ final ProfileNamespaceURIPatternMatchResult rhsPatternMatch) {
+ this.lhsPatternMatch = lhsPatternMatch;
+ this.rhsPatternMatch = rhsPatternMatch;
+ }
+
+ /**
+ * Left-hand side pattern match given when constructing this comparison.
+ *
+ * @return left-hand side pattern match
+ */
+ public ProfileNamespaceURIPatternMatchResult getLHSPatternMatch() {
+ return lhsPatternMatch;
+ }
+
+ /**
+ * Right-hand side pattern match given when constructing this comparison.
+ *
+ * @return second pattern match
+ */
+ public ProfileNamespaceURIPatternMatchResult getRHSPatternMatch() {
+ return rhsPatternMatch;
+ }
+
+ /**
+ * This comparison is valid if both pattern matches have matched.
+ *
+ * @return true if both pattern matches are valid, false otherwise
+ */
+ public boolean isValid() {
+ return getLHSPatternMatch() != null && getRHSPatternMatch() != null
+ && getLHSPatternMatch().hasMatched() && getRHSPatternMatch().hasMatched();
+ }
+
+ /**
+ * Returns true if both pattern matches have the same {@link ProfileNamespaceURIPatternMatchResult#getVersion() version string}.
+ * If this comparison is invalid, then this method returns false.
+ *
+ * @return true if both pattern matches refer to the same version, false otherwise or if this comparison is invalid
+ */
+ public boolean isEqualVersion() {
+ return isValid()
+ && getLHSPatternMatch().getVersion().equals(getRHSPatternMatch().getVersion());
+ }
+
+ /**
+ * Returns true if both pattern matches have the same {@link ProfileNamespaceURIPatternMatchResult#getVersionlessNamespaceURI() versionless namespace URI}.
+ * If this comparison is invalid, then this method returns false.
+ *
+ * @return true if both pattern matches refer to the same versionless namespace URI, false otherwise or if this comparison is invalid
+ */
+ public boolean isEqualVersionlessNamespaceURI() {
+ return isValid()
+ && getLHSPatternMatch().getVersionlessNamespaceURI().equals(getRHSPatternMatch().getVersionlessNamespaceURI());
+ }
+
+ /**
+ * Returns true if both pattern matches have the same {@link ProfileNamespaceURIPatternMatchResult#getNamespaceURI() namespace URI}.
+ * If this comparison is invalid, then this method returns false.
+ *
+ * @return true if both pattern matches refer to the same namespace URI, false otherwise or if this comparison is invalid
+ */
+ public boolean isEqualNamespaceURI() {
+ return isValid()
+ && getLHSPatternMatch().getNamespaceURI().equals(getRHSPatternMatch().getNamespaceURI());
+ }
+
+ @Override
+ public String toString() {
+ if (!isValid()) {
+ return "Invalid comparison.";
+ }
+ return getLHSPatternMatch() + " versus " + getRHSPatternMatch();
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternMatchResult.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternMatchResult.java
new file mode 100644
index 00000000000..7238931d98b
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternMatchResult.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Martin Fleck - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.uml.modelrepair.internal.uripattern;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.regex.MatchResult;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class evaluates a {@link Pattern#matches(String, CharSequence) pattern match} with regards to a {@link ProfileNamespaceURIPattern}
+ * and provides convenience methods to access the profile-identifying part (without version) and versioning part of the matched URI.
+ *
+ * @author Martin Fleck <mfleck@eclipsesource.com>
+ */
+public class ProfileNamespaceURIPatternMatchResult {
+
+ /** Constant representing an unsuccessful match */
+ public static final ProfileNamespaceURIPatternMatchResult NO_MATCH = new ProfileNamespaceURIPatternMatchResult(null, null);
+
+ /** Result from the matching process, null if the matching was not successful */
+ private MatchResult regexMatchResult;
+
+ /** Format used to format the versioning part of the matched URI */
+ private MessageFormat versionFormat;
+
+ /** Cached strings for all group parts in the match */
+ private String[] groups;
+
+ /** Cached strings for all non-group parts in the match */
+ private String[] nonGroups;
+
+ /** The entire matched namespace URI */
+ private String namespaceURI;
+
+ /** The profile-identifying, versionless part of the match, i.e., a concatenation of the non-group parts in the match */
+ private String versionlessNamespaceURI;
+
+ /** The formatted versioning string of the match based on the given message format and the matched groups */
+ private String version;
+
+ /**
+ * Creates a new match result based on the given matcher.
+ * If the matcher does not match the {@link Matcher#matches() entire string}, then this match result is considered {@link #hasMatched() unsuccessful}
+ * and all methods querying the result will return null.
+ *
+ * @param matcher
+ * match engine
+ * @see ProfileNamespaceURIPattern
+ * @see ProfileNamespaceURIPatternRegistry
+ */
+ public ProfileNamespaceURIPatternMatchResult(final Matcher matcher) {
+ this(matcher, null);
+ }
+
+ /**
+ * Creates a new match based on the given matcher and the provided format for the versioning part of the match.
+ * If the matcher does not match the {@link Matcher#matches() entire string}, then this match result is considered {@link #hasMatched() unsuccessful}
+ * and all methods querying the result will return null.
+ * The version format allows for individual formatting of the extracted version information and needs to conform to the {@link MessageFormat}.
+ * Indices in the format correspond to the indices of the groups matched by the pattern, e.g., {0} refers to group zero holding the entire pattern and {1} refers to the first matched group.
+ * The version format will only be used if the match is successful and is used to produce the {@link #getVersion() version string} of the matched URI.
+ *
+ * @param matcher
+ * match engine
+ * @param versionFormat
+ * format for the versioning part of the matched namespace URI
+ * @see ProfileNamespaceURIPattern
+ * @see ProfileNamespaceURIPatternRegistry
+ */
+ public ProfileNamespaceURIPatternMatchResult(final Matcher matcher, final MessageFormat versionFormat) {
+ if (matcher != null && matcher.matches()) {
+ this.regexMatchResult = matcher.toMatchResult();
+ this.versionFormat = versionFormat;
+ }
+ }
+
+ /**
+ * Returns the format used to produce the {@link #getVersion() version string} from all version parts extracted from the matched URI.
+ * Indices in the format correspond to the indices of the groups matched by the pattern, e.g., {0} refers to group zero holding the entire pattern and {1} refers to the first matched group.
+ *
+ * @return the versionFormat
+ */
+ public MessageFormat getVersionFormat() {
+ return versionFormat;
+ }
+
+ /**
+ * Returns true if a successful match could be produced for the given URI considering the underlying pattern, false otherwise.
+ * If no successful match could be produced, all methods querying the result will return null.
+ *
+ * @return true if the match was successful, false otherwise.
+ */
+ public boolean hasMatched() {
+ return getRegexMatchResult() != null;
+ }
+
+ /**
+ * Returns the entire matched namespace URI. If the pattern did not match, null is returned.
+ *
+ * @return matched namespace URI or null
+ */
+ public String getNamespaceURI() {
+ if (!hasMatched()) {
+ return null;
+ }
+ if (namespaceURI == null) {
+ namespaceURI = getRegexMatchResult().group(0);
+ }
+ return namespaceURI;
+ }
+
+ /**
+ * Returns the versionless namespace URI of the matched URI or null the underlying pattern was not matched.
+ * The versionless namespace URI may be used to identify a profile, independent of its version.
+ *
+ * @return profile-identifying, versionless namespace URI or null if there is no match
+ */
+ public String getVersionlessNamespaceURI() {
+ if (!hasMatched()) {
+ return null;
+ }
+ if (versionlessNamespaceURI == null) {
+ versionlessNamespaceURI = String.join("", getNonGroups());
+ }
+ return versionlessNamespaceURI;
+ }
+
+ /**
+ * Returns the version of the matched namespace URI or null if the underlying pattern was not matched.
+ * The version string is formatted using the {@link #getVersionFormat() version format} provided when constructing this result.
+ * If no format was provided, the version parts get concatenated via comma.
+ *
+ * @return version string of the matched namespace URI or null if there is no match
+ */
+ public String getVersion() {
+ if (!hasMatched()) {
+ return null;
+ }
+ if (version == null) {
+ if (versionFormat != null) {
+ version = versionFormat.format(getGroups());
+ } else {
+ // by default just concatenate version parts via comma without the entire match (group 0)
+ version = String.join(",", Arrays.copyOfRange(getGroups(), 1, getGroups().length));
+ }
+ }
+ return version;
+ }
+
+ /**
+ * Returns the Regex match result produced from the matcher given in the constructor.
+ * If there was no match, the match result is null.
+ *
+ * @return match result or null if there is no match
+ */
+ protected MatchResult getRegexMatchResult() {
+ return regexMatchResult;
+ }
+
+ /**
+ * Returns all group strings of the underlying match result. If no match result is present, null is returned.
+ * The indices of the groups match the indices of the returned array.
+ * Please note that group zero (at index zero) holds the entire matched pattern.
+ *
+ * @return group strings or null
+ */
+ protected String[] getGroups() {
+ if (!hasMatched()) {
+ return null;
+ }
+ if (groups == null) {
+ final int groupCount = getRegexMatchResult().groupCount();
+ // group 0 has complete match and is not included in group count
+ groups = new String[groupCount + 1];
+ for (int i = 0; i <= groupCount; i++) {
+ groups[i] = getRegexMatchResult().group(i);
+ }
+ }
+ return groups;
+ }
+
+ /**
+ * Returns all non-group strings of the underlying match result.
+ * If no match result is present, null is returned.
+ *
+ * @return non-group strings or null
+ */
+ protected String[] getNonGroups() {
+ if (!hasMatched()) {
+ return null;
+ }
+ if (nonGroups == null) {
+ final int groupCount = getRegexMatchResult().groupCount();
+ final ArrayList<String> nonGroupList = new ArrayList<String>();
+ String nonGroup;
+ int start = getRegexMatchResult().start();
+ for (int i = 1; i <= groupCount; i++) {
+ nonGroup = getNamespaceURI().substring(start, getRegexMatchResult().start(i));
+ if (!nonGroup.isEmpty()) {
+ nonGroupList.add(nonGroup);
+ }
+ start = getRegexMatchResult().end(i);
+ }
+ nonGroup = getNamespaceURI().substring(start, getRegexMatchResult().end());
+ if (!nonGroup.isEmpty()) {
+ nonGroupList.add(nonGroup);
+ }
+ nonGroups = nonGroupList.toArray(new String[nonGroupList.size()]);
+ }
+ return nonGroups;
+ }
+
+ @Override
+ public String toString() {
+ if (!hasMatched()) {
+ return "No match.";
+ }
+ return getVersionlessNamespaceURI() + " [" + getVersion() + "]";
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternRegistry.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternRegistry.java
new file mode 100644
index 00000000000..d044c04b762
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternRegistry.java
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Martin Fleck - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.uml.modelrepair.internal.uripattern;
+
+import static org.eclipse.papyrus.uml.modelrepair.Activator.PLUGIN_ID;
+import static org.eclipse.papyrus.uml.modelrepair.Activator.log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.Platform;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Lists;
+
+/**
+ * This registry holds all profile namespace URI patterns that have been provided through the profile namespace
+ * URI pattern extension point or via the API of this registry.
+ *
+ * @author Martin Fleck <mfleck@eclipsesource.com>
+ */
+public class ProfileNamespaceURIPatternRegistry {
+
+ /** Singleton instance of this registry */
+ public static final ProfileNamespaceURIPatternRegistry INSTANCE = new ProfileNamespaceURIPatternRegistry();
+
+ /** ID under which extension points are registered */
+ private static final String EXTENSION_ID = PLUGIN_ID + ".profileNamespaceURIPattern"; //$NON-NLS-1$
+
+ /** Name of the profile namespace URI pattern configuration element */
+ private static final String NAME = "profileNamespaceURIPattern"; //$NON-NLS-1$
+
+ /** Attribute of the profile namespace URI pattern configuration element holding the URI pattern */
+ private static final String URI_PATTERN = "uriPattern"; //$NON-NLS-1$
+
+ /** Attribute of the profile namespace URI pattern configuration element holding the version format */
+ private static final String VERSION_FORMAT = "versionFormat"; //$NON-NLS-1$
+
+ /** List of registered profile namespace URI patterns */
+ private List<ProfileNamespaceURIPattern> profileNamespaceURIPatterns = new ArrayList<ProfileNamespaceURIPattern>();
+
+ /**
+ * Private constructor to avoid creation in favor of singleton instance.
+ */
+ private ProfileNamespaceURIPatternRegistry() {
+ initFromExtensionPoints();
+ }
+
+ /**
+ * Reads profile namespace URI patterns from the extension points and adds them to the list of patterns.
+ */
+ private void initFromExtensionPoints() {
+ final IConfigurationElement[] config = Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_ID);
+
+ // read data from plugins
+ for (IConfigurationElement element : config) {
+ try {
+ if (NAME.equals(element.getName())) {
+ ProfileNamespaceURIPattern pattern = processProfileNamespaceURIPattern(element);
+ register(pattern);
+ }
+ } catch (Exception ex) {
+ log.error(ex);
+ }
+ }
+ }
+
+ /**
+ * Reads the necessary data from the provided configuration element to create a new profile namespace URI pattern.
+ *
+ * @param element
+ * configuration element
+ * @return newly created profile namespace URI pattern
+ */
+ private ProfileNamespaceURIPattern processProfileNamespaceURIPattern(IConfigurationElement element) {
+ final String uriPattern = element.getAttribute(URI_PATTERN);
+ final String versionFormat = element.getAttribute(VERSION_FORMAT); // is optional, may return null
+ return new ProfileNamespaceURIPattern(uriPattern, versionFormat);
+ }
+
+ /**
+ * Returns an unmodifiable list of all registered profile namespace URI patterns.
+ *
+ * @return list of registered profile namespace URI patterns
+ */
+ public List<ProfileNamespaceURIPattern> getProfileNamespaceURIPatterns() {
+ return Collections.unmodifiableList(profileNamespaceURIPatterns);
+ }
+
+ /**
+ * Adds the provided profile namespace URI pattern to this registry.
+ *
+ * @param profileNamespaceURIPattern
+ * pattern to be registered
+ */
+ public void register(ProfileNamespaceURIPattern profileNamespaceURIPattern) {
+ profileNamespaceURIPatterns.add(profileNamespaceURIPattern);
+ }
+
+ /**
+ * Removes the given profile namespace URI patterns from this registry.
+ * If the pattern can not be found, the registry remains unchanged.
+ *
+ * @param profileNamespaceURIPattern
+ * pattern to be unregistered, if present
+ */
+ public void unregister(ProfileNamespaceURIPattern profileNamespaceURIPattern) {
+ profileNamespaceURIPatterns.remove(profileNamespaceURIPattern);
+ }
+
+ /**
+ * Returns an {@link Optional} containing the first pattern that matches the given uri,
+ * if such a pattern exists.
+ *
+ * @param namespaceURI
+ * namespace URI to be matched
+ * @return Optional containing the first matching pattern, if such a pattern exists
+ */
+ public Optional<ProfileNamespaceURIPattern> tryFindPattern(String namespaceURI) {
+ for (ProfileNamespaceURIPattern pattern : getProfileNamespaceURIPatterns()) {
+ ProfileNamespaceURIPatternMatchResult match = pattern.match(namespaceURI);
+ if (match.hasMatched()) {
+ return Optional.of(pattern);
+ }
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Returns a list of patterns that match the given namespace URI.
+ * If no such pattern exist, an empty list is returned.
+ *
+ * @param namespaceURI
+ * namespace URI to be matched
+ * @return list of matching patterns
+ */
+ public List<ProfileNamespaceURIPattern> findPatterns(String namespaceURI) {
+ List<ProfileNamespaceURIPattern> patterns = Lists.newArrayList();
+ for (ProfileNamespaceURIPattern pattern : getProfileNamespaceURIPatterns()) {
+ ProfileNamespaceURIPatternMatchResult match = pattern.match(namespaceURI);
+ if (match.hasMatched()) {
+ patterns.add(pattern);
+ }
+ }
+ return patterns;
+ }
+
+ /**
+ * Returns an {@link Optional} containing the first pattern match that matches the given namespace URI,
+ * if such a pattern match exists.
+ *
+ * @param namespaceURI
+ * namespace URI to be matched
+ * @return Optional containing the first matching pattern match, if such a pattern match exists
+ */
+ public Optional<ProfileNamespaceURIPatternMatchResult> tryFindMatch(String namespaceURI) {
+ for (ProfileNamespaceURIPattern pattern : getProfileNamespaceURIPatterns()) {
+ ProfileNamespaceURIPatternMatchResult match = pattern.match(namespaceURI);
+ if (match.hasMatched()) {
+ return Optional.of(match);
+ }
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Returns a list of pattern matches that match the given namespace URI.
+ * If no such pattern match exist, an empty list is returned.
+ *
+ * @param namespaceURI
+ * namespace URI to be matched
+ * @return list of matching pattern matches
+ */
+ public List<ProfileNamespaceURIPatternMatchResult> findMatches(String namespaceURI) {
+ List<ProfileNamespaceURIPatternMatchResult> matches = Lists.newArrayList();
+ for (ProfileNamespaceURIPattern pattern : getProfileNamespaceURIPatterns()) {
+ ProfileNamespaceURIPatternMatchResult match = pattern.match(namespaceURI);
+ if (match.hasMatched()) {
+ matches.add(match);
+ }
+ }
+ return matches;
+ }
+
+ /**
+ * Returns an {@link Optional} containing the first valid pattern comparison that matches both namespace URIs,
+ * if such a comparison exists.
+ *
+ * @param lhsNamespaceUri
+ * left-hand side namespace URI of the comparison
+ * @param rhsNamespaceUri
+ * right-hand side namespace URI of the comparison
+ * @return Optional containing the first valid pattern comparison, if such a comparison exists
+ */
+ public Optional<ProfileNamespaceURIPatternComparison> tryFindComparison(String lhsNamespaceUri, String rhsNamespaceUri) {
+ for (ProfileNamespaceURIPattern pattern : getProfileNamespaceURIPatterns()) {
+ ProfileNamespaceURIPatternComparison comparison = pattern.compare(lhsNamespaceUri, rhsNamespaceUri);
+ if (comparison.isValid()) {
+ return Optional.of(comparison);
+ }
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Returns a list of valid pattern comparisons that match both namespace URIs.
+ * If no such comparison exist, an empty list is returned.
+ *
+ * @param lhsNamespaceUri
+ * left-hand side namespace URI of the comparison
+ * @param rhsNamespaceUri
+ * right-hand side namespace URI of the comparison
+ * @return list of valid comparisons between the given namespace URIs
+ */
+ public List<ProfileNamespaceURIPatternComparison> findComparisons(String lhsNamespaceUri, String rhsNamespaceUri) {
+ List<ProfileNamespaceURIPatternComparison> comparisons = Lists.newArrayList();
+ for (ProfileNamespaceURIPattern pattern : getProfileNamespaceURIPatterns()) {
+ ProfileNamespaceURIPatternComparison comparison = pattern.compare(lhsNamespaceUri, rhsNamespaceUri);
+ if (comparison.isValid()) {
+ comparisons.add(comparison);
+ }
+ }
+ return comparisons;
+ }
+}
diff --git a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/META-INF/MANIFEST.MF b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/META-INF/MANIFEST.MF
index fe304630c13..59ce8e0e82a 100644
--- a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/META-INF/MANIFEST.MF
+++ b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/META-INF/MANIFEST.MF
@@ -6,6 +6,7 @@ Require-Bundle: org.junit;bundle-version="4.10.0",
org.eclipse.uml2.uml;bundle-version="[5.2.0,6.0.0)",
org.eclipse.papyrus.infra.emf.readonly;bundle-version="[2.0.0,3.0.0)"
Export-Package: org.eclipse.papyrus.uml.modelrepair.internal.stereotypes,
+ org.eclipse.papyrus.uml.modelrepair.internal.uripattern,
org.eclipse.papyrus.uml.modelrepair.tests
Bundle-Vendor: %providerName
Bundle-Version: 1.2.0.qualifier
diff --git a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/plugin.xml b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/plugin.xml
index c8f9d20ccbe..719f76fd306 100644
--- a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/plugin.xml
+++ b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/plugin.xml
@@ -41,4 +41,11 @@
path="pathmap://modelrepairtests/dynamicprofiles/dynamic.profile.uml">
</profile>
</extension>
+ <extension
+ point="org.eclipse.papyrus.uml.modelrepair.profileNamespaceURIPattern">
+ <profileNamespaceURIPattern
+ uriPattern="^http://www\.eclipse\.org/my/profile/test/([^/]+)/Language/.*$"
+ versionFormat="#{1}#">
+ </profileNamespaceURIPattern>
+ </extension>
</fragment>
diff --git a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/resources/regression/bug496307/model.uml b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/resources/regression/bug496307/model.uml
new file mode 100644
index 00000000000..a23a34b54e0
--- /dev/null
+++ b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/resources/regression/bug496307/model.uml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xmi:XMI xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:PackageA="http://www.eclipse.org/product/0.6.0/Language/PackageA"
+ xmlns:PackageB="http://www.eclipse.org/product/0.6.0/Language/PackageB"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
+ xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML"
+ xsi:schemaLocation="
+ http://www.eclipse.org/product/0.6.0/Language/PackageA http://www.eclipse.org/product/0.6.0/Language#//packageA
+ http://www.eclipse.org/product/0.6.0/Language/PackageB http://www.eclipse.org/product/0.6.0/Language#//packageB">
+ <uml:Model xmi:id="_j7ML4CdYEea7OLrFgBltsw" name="RootElement">
+ <packagedElement xmi:type="uml:Class" xmi:id="_mPfJwCdYEea7OLrFgBltsw" name="MyBlock"/>
+ <profileApplication xmi:type="uml:ProfileApplication" xmi:id="_j_rqUCdYEea7OLrFgBltsw">
+ <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_j_rqUSdYEea7OLrFgBltsw" source="http://www.eclipse.org/uml2/2.0.0/UML">
+ <references xmi:type="ecore:EPackage" href="http://www.eclipse.org/product/0.6.0/Language#//packageB"/>
+ </eAnnotations>
+ <appliedProfile xmi:type="uml:Profile" href="pathmap://NO_PROFILE/Language.profile.uml#_Gx8MgLX7EduFmqQsrNB9lw"/>
+ </profileApplication>
+ <profileApplication xmi:type="uml:ProfileApplication" xmi:id="_j_sRYCdYEea7OLrFgBltsw">
+ <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_j_sRYSdYEea7OLrFgBltsw" source="http://www.eclipse.org/uml2/2.0.0/UML">
+ <references xmi:type="ecore:EPackage" href="http://www.eclipse.org/product/0.6.0/Language#//packageA"/>
+ </eAnnotations>
+ <appliedProfile xmi:type="uml:Profile" href="pathmap://NO_PROFILE/Language.profile.uml#_fSw28LX7EduFmqQsrNB9lw"/>
+ </profileApplication>
+ </uml:Model>
+ <PackageA:Block xmi:id="_mPjbMCdYEea7OLrFgBltsw" isEncapsulated="true" base_Class="_mPfJwCdYEea7OLrFgBltsw"/>
+ <PackageB:ViewPoint xmi:id="_N_15cCdZEea7OLrFgBltsw" base_Class="_mPfJwCdYEea7OLrFgBltsw" purpose="This is just for testing."/>
+</xmi:XMI>
diff --git a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeRepairRegressionTest.java b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeRepairRegressionTest.java
index e2eb655806a..c377703dd9a 100644
--- a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeRepairRegressionTest.java
+++ b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeRepairRegressionTest.java
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014, 2016 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 v1.0
* which accompanies this distribution, and is available at
@@ -9,10 +9,12 @@
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
* Christian W. Damus - bugs 455248, 455329, 436666, 458736, 459488, 488791
+ * Martin Fleck - bug 496307
*
*/
package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
+import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
@@ -36,17 +38,22 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.xml.type.AnyType;
import org.eclipse.papyrus.infra.core.utils.TransactionHelper;
+import org.eclipse.papyrus.infra.tools.util.PlatformHelper;
import org.eclipse.papyrus.junit.framework.classification.tests.AbstractPapyrusTest;
import org.eclipse.papyrus.junit.utils.rules.AbstractHouseKeeperRule.CleanUp;
import org.eclipse.papyrus.junit.utils.rules.HouseKeeper;
import org.eclipse.papyrus.junit.utils.rules.ModelSetFixture;
import org.eclipse.papyrus.junit.utils.rules.PluginResource;
import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.StereotypeApplicationRepairSnippetTest.MyStereotypeApplicationRepairSnippet;
+import org.eclipse.papyrus.uml.modelrepair.internal.uripattern.ProfileNamespaceURIPattern;
+import org.eclipse.papyrus.uml.modelrepair.internal.uripattern.ProfileNamespaceURIPatternRegistry;
import org.eclipse.papyrus.uml.modelrepair.ui.IZombieStereotypePresenter;
import org.eclipse.uml2.common.util.UML2Util;
import org.eclipse.uml2.uml.Class;
@@ -62,6 +69,8 @@ import org.junit.Test;
import com.google.common.base.Function;
import com.google.common.base.Functions;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -99,7 +108,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that a scenario involving nested profiles and profile applications in nested packages that are all actually
* well-formed does not trigger the repair function.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=434302
*/
@Test
@@ -111,7 +120,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that a scenario involving a nested profile gone AWOL in profile applications in a nested packages is
* correctly repaired.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=434302
*/
@Test
@@ -140,7 +149,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that a scenario involving a single nested profile schema declaration gone AWOL in two different profile applications
* in two different nested packages is correctly repaired.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=434302
*/
@Test
@@ -180,7 +189,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that a scenario involving well-formed stereotypes contained in a simple package nested in a profile
* does not trigger the repair function.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=436666
*/
@Test
@@ -193,7 +202,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that a scenario involving stereotypes from a nested EPackage gone AWOL, which EPackage is defined by a nested
* simple package in the UML profile, is correctly repaired.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=436666
*/
@Test
@@ -222,7 +231,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that a scenario involving non-UML root elements that are recognizably not stereotype
* applications do not trigger the repair function.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=436666
*/
@Test
@@ -236,7 +245,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
* Tests that a sub-united model in which package units do not repeat profile applications,
* but rather just inherit them from parent units, such as might be imported from some other
* UML tool, does not falsely trigger repair.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=455248
*/
@Test
@@ -249,7 +258,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that a model applying a registered dynamic profile does not detect spurious broken
* stereotype applications.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=455329
*/
@Test
@@ -261,7 +270,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that orphaned stereotype instances are correctly detected where they are of the currently applied profile schema.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=436666
*/
@Test
@@ -280,7 +289,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that orphaned stereotype instances are correctly detected where they are of a profile version that is not currently applied.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=436666
*/
@Test
@@ -302,7 +311,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
* but rather just inherit them from parent units, such as might be imported from some other
* UML tool, does not falsely trigger repair in the case where sub-units are lazily loaded
* by cross-references after the main model has been loaded.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=458736
*/
@Test
@@ -318,7 +327,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
/**
* Tests that a scenario involving a malformed XSI schema-location for a profile schema in a non-package model fragment
* (sub-unit resource) is correctly detected and repaired.
- *
+ *
* @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=459488
*/
@Test
@@ -343,6 +352,105 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
assertThat("Stereotype1 application in wrong resource", class1.getStereotypeApplication(stereotype1).eResource(), is(class1.eResource()));
}
+ /**
+ * Tests that bug 496307 is present and there are cases where zombie stereotypes are not correctly
+ * assigned to the expected package, because the namespace URI (schema) is not understood correctly.
+ *
+ * In the test model we have one class with two stereotypes applied:
+ * - Block from PackageA with schema http://www.eclipse.org/product/0.6.0/Language/PackageA
+ * - ViewPoint from PackageB with schema http://www.eclipse.org/product/0.6.0/Language/PackageB
+ *
+ * Both schemas do not conform to the default pattern, so they are reduced to the schema
+ * http://www.eclipse.org/product/0.6.0/Language#/ during comparison.
+ * As a result, both zombie stereotypes are assigned to both schemas and wrongly assigned
+ * zombie stereotypes may be deleted.
+ *
+ * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=496307
+ */
+ @Test
+ @Bug("496307")
+ @PluginResource("/resources/regression/bug496307/model.uml")
+ public void incorrectZombieGroupingWithoutProfileNamespaceURIPattern_bug496307() {
+ Collection<? extends IAdaptable> schemata = zombies.getZombieSchemas();
+ assertThat("Expected two schemata", schemata.size(), is(2));
+
+ Optional<? extends IAdaptable> packageA = Iterables.tryFind(schemata,
+ ePackage("http://www.eclipse.org/product/0.6.0/Language/PackageA"));
+ assertThat("PackageA not found", packageA.isPresent());
+
+ Optional<? extends IAdaptable> packageB = Iterables.tryFind(schemata,
+ ePackage("http://www.eclipse.org/product/0.6.0/Language/PackageB"));
+ assertThat("PackageB not found", packageB.isPresent());
+
+ Collection<? extends EObject> packageAzombies = zombies.getZombies(packageA.get());
+ assertThat("Expected two zombies in PackageA", packageAzombies.size(), is(2));
+
+ Collection<? extends EObject> packageBzombies = zombies.getZombies(packageB.get());
+ assertThat("Expected two zombies in PackageB", packageBzombies.size(), is(2));
+
+ assertThat("Same zombies in PackageA and PackageB expected", packageAzombies.containsAll(packageBzombies));
+ }
+
+ /**
+ * Tests that bug 496307 is resolved through {@link ProfileNamespaceURIPattern}s which provide a mechanism to
+ * understand namespace URI schemas.
+ *
+ * In the test model we have one class with two stereotypes applied:
+ * - Block from PackageA with package schema http://www.eclipse.org/product/0.6.0/Language/PackageA
+ * - ViewPoint from PackageB with package schema http://www.eclipse.org/product/0.6.0/Language/PackageB
+ *
+ * Both schemas do not conform to the default pattern, but we provide the namespace URI pattern
+ * ^http://www\\.eclipse\\.org/product/([^/]+)/Language/.*$ during comparison.
+ * As a result, both zombie stereotypes are correctly assigned to their respective schema.
+ *
+ * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=496307
+ */
+ @Test
+ @Bug("496307")
+ @PluginResource("/resources/regression/bug496307/model.uml")
+ public void correctZombieGroupingWithProfileNamespaceURIPattern_bug496307() {
+ ProfileNamespaceURIPatternRegistry registry = ProfileNamespaceURIPatternRegistry.INSTANCE;
+ ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(
+ "^http://www\\.eclipse\\.org/product/([^/]+)/Language/.*$");
+
+ try {
+ registry.register(pattern);
+
+ Collection<? extends IAdaptable> schemata = zombies.getZombieSchemas();
+
+ assertThat("Expected two schemata", schemata.size(), is(2));
+
+ Optional<? extends IAdaptable> packageA = Iterables.tryFind(schemata,
+ ePackage("http://www.eclipse.org/product/0.6.0/Language/PackageA"));
+ assertThat("PackageA not found", packageA.isPresent());
+
+ Optional<? extends IAdaptable> packageB = Iterables.tryFind(schemata,
+ ePackage("http://www.eclipse.org/product/0.6.0/Language/PackageB"));
+ assertThat("PackageB not found", packageB.isPresent());
+
+ Collection<? extends EObject> packageAzombies = zombies.getZombies(packageA.get());
+ assertThat("Expected one zombies in PackageA", packageAzombies.size(), is(1));
+
+ EObject packageAzombie = packageAzombies.iterator().next();
+ assertThat("Expected zombie stereotype (AnyType)", packageAzombie, instanceOf(AnyType.class));
+
+ EClass packageAzombieClass = packageAzombie.eClass();
+ assertThat("PackageA zombie should be Block", packageAzombieClass.getName(), is("Block"));
+
+ Collection<? extends EObject> packageBzombies = zombies.getZombies(packageB.get());
+ assertThat("Expected one zombies in PackageB", packageBzombies.size(), is(1));
+
+ EObject packageBzombie = packageBzombies.iterator().next();
+ assertThat("Expected zombie stereotype (AnyType)", packageBzombie, instanceOf(AnyType.class));
+
+ EClass packageBzombieClass = packageBzombie.eClass();
+ assertThat("PackageB zombie should be ViewPoint", packageBzombieClass.getName(), is("ViewPoint"));
+ } finally {
+ // ensure that the pattern is unregistered for further tests
+ registry.unregister(pattern);
+ }
+ }
+
//
// Test framework
//
@@ -425,7 +533,7 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
}), "dispose", modelSet.getResourceSet());
}
- @Bug({ "436666bis", "455248", "455329" })
+ @Bug({ "436666bis", "455248", "455329", "496307" })
protected MyStereotypeApplicationRepairSnippet createSimpleFixture() {
return houseKeeper.cleanUpLater(new MyStereotypeApplicationRepairSnippet(null, Functions.constant((Profile) null)), "dispose", modelSet.getResourceSet());
}
@@ -506,6 +614,16 @@ public class StereotypeRepairRegressionTest extends AbstractPapyrusTest {
sync.await();
}
+ Predicate<IAdaptable> ePackage(final String uri) {
+ return new Predicate<IAdaptable>() {
+ @Override
+ public boolean apply(IAdaptable adaptable) {
+ EPackage ePackage = PlatformHelper.getAdapter(adaptable, EPackage.class);
+ return ePackage != null && ePackage.getNsURI() != null && ePackage.getNsURI().equals(uri);
+ }
+ };
+ }
+
//
// Nested types
//
diff --git a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternTest.java b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternTest.java
new file mode 100644
index 00000000000..84c336563f8
--- /dev/null
+++ b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/internal/uripattern/ProfileNamespaceURIPatternTest.java
@@ -0,0 +1,545 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Martin Fleck - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.uml.modelrepair.internal.uripattern;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import org.eclipse.papyrus.junit.framework.classification.tests.AbstractPapyrusTest;
+import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.StereotypeRepairRegressionTest;
+import org.junit.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+/**
+ * Tests for {@link ProfileNamespaceURIPattern}s and the related functionality.
+ * The extended profile migration capabilities provided through the profile namespace URI patterns is tested in {@link StereotypeRepairRegressionTest}.
+ *
+ * @author Martin Fleck <mfleck@eclipsesource.com>
+ */
+public class ProfileNamespaceURIPatternTest extends AbstractPapyrusTest {
+
+ // no version in URI
+
+ private static final String NO_VERSION_PATTERN = "^http://www\\.eclipse\\.org/my/profile/Language/.*$"; //$NON-NLS-1$
+
+ private static final String NO_VERSION_FORMAT = "{0}"; //$NON-NLS-1$
+
+ private static final String NO_VERSION_A_URI = "http://www.eclipse.org/my/profile/Language/PackageA"; //$NON-NLS-1$
+
+ private static final String NO_VERSION_B_URI = "http://www.eclipse.org/my/profile/Language/PackageB"; //$NON-NLS-1$
+
+ private static final String NO_VERSION_VERSION_DEFAULT = ""; //$NON-NLS-1$
+
+ // single version in URI
+
+ private static final String SINGLE_VERSION_PATTERN = "^http://www\\.eclipse\\.org/my/profile/version/([^/]+)/Language/.*$"; //$NON-NLS-1$
+
+ private static final String SINGLE_VERSION_FORMAT = "-{1}-"; //$NON-NLS-1$
+
+ private static final String SINGLE_VERSION_A7_URI = "http://www.eclipse.org/my/profile/version/7/Language/PackageA"; //$NON-NLS-1$
+
+ private static final String SINGLE_VERSION_A7_VERSIONLESS_URI = "http://www.eclipse.org/my/profile/version//Language/PackageA"; //$NON-NLS-1$
+
+ private static final String SINGLE_VERSION_A7_VERSION_DEFAULT = "7"; //$NON-NLS-1$
+
+ private static final String SINGLE_VERSION_A7_VERSION_FORMAT = "-7-"; //$NON-NLS-1$
+
+ private static final String SINGLE_VERSION_B7_URI = "http://www.eclipse.org/my/profile/version/7/Language/PackageB"; //$NON-NLS-1$
+
+ private static final String SINGLE_VERSION_A8_URI = "http://www.eclipse.org/my/profile/version/8/Language/PackageA"; //$NON-NLS-1$
+
+ private static final String SINGLE_VERSION_NONMATCHING_URI = "http://www.eclipse.org/different/profile/version/7/Language/PackageA"; //$NON-NLS-1$
+
+ // multiple versions in URI
+
+ private static final String MULTI_VERSION_PATTERN = "^http://www\\.eclipse\\.org/my/profile/version/([^/]+)/Language/([^/]+)/.*$"; //$NON-NLS-1$
+
+ private static final String MULTI_VERSION_FORMAT = "{1} - {2}"; //$NON-NLS-1$
+
+ private static final String MULTI_VERSION_A7_701_URI = "http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageA"; //$NON-NLS-1$
+
+ private static final String MULTI_VERSION_A7_701_VERSIONLESS_URI = "http://www.eclipse.org/my/profile/version//Language//PackageA"; //$NON-NLS-1$
+
+ private static final String MULTI_VERSION_A7_701_VERSION_DEFAULT = "7,7.0.1"; // comma-separated //$NON-NLS-1$
+
+ private static final String MULTI_VERSION_A7_701_VERSION_FORMAT = "7 - 7.0.1"; //$NON-NLS-1$
+
+ private static final String MULTI_VERSION_B7_701_URI = "http://www.eclipse.org/my/profile/version/7/Language/7.0.1/PackageB"; //$NON-NLS-1$
+
+ private static final String MULTI_VERSION_A7_702_URI = "http://www.eclipse.org/my/profile/version/7/Language/7.0.2/PackageA"; //$NON-NLS-1$
+
+ // non-matching pattern
+
+ private static final String NON_MATCHING_PATTERN = "^http://www\\.eclipse\\.org/no/match/version/([^/]+)/Language/([^/]+)/.*$"; //$NON-NLS-1$
+
+ // pattern registered via extension point
+
+ private static final String EXTENSION_POINT_PATTERN = "^http://www\\.eclipse\\.org/my/profile/test/([^/]+)/Language/.*$"; //$NON-NLS-1$
+
+ private static final String EXTENSION_POINT_URI = "http://www.eclipse.org/my/profile/test/7/Language/PackageA"; //$NON-NLS-1$
+
+ private static final String EXTENSION_POINT_VERSIONLESS_URI = "http://www.eclipse.org/my/profile/test//Language/PackageA"; //$NON-NLS-1$
+
+ private static final String EXTENSION_POINT_VERSION = "#7#"; // custom version format: #{0}# //$NON-NLS-1$
+
+
+ /**
+ * Predicate that evaluates whether a specific pattern is the one we registered via an extension point.
+ *
+ * @return new predicate
+ */
+ protected static Predicate<ProfileNamespaceURIPattern> isExtensionPointPattern() {
+ return new Predicate<ProfileNamespaceURIPattern>() {
+ @Override
+ public boolean apply(ProfileNamespaceURIPattern pattern) {
+ return pattern.getRegexPattern() != null && EXTENSION_POINT_PATTERN.equals(pattern.getRegexPattern().pattern()) &&
+ pattern.getVersionFormat() != null;
+ }
+ };
+ }
+
+ // no version matching behavior
+
+ /**
+ * Tests whether the pattern match yields the correct results for an URI with no version part
+ * and the default version format. When there is no versioning information, the versionless URI
+ * and the given URI should be the same.
+ */
+ @Test
+ public void matchNoVersionCorrectURIDefaultVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(NO_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternMatchResult match = pattern.match(NO_VERSION_A_URI);
+
+ assertThat("Pattern should have matched.", match.hasMatched());
+ assertThat("Matched namespace URI should be equal to given namesapce URI.",
+ match.getNamespaceURI(), is(NO_VERSION_A_URI));
+ assertThat("Wrong extracted versionless namespace URI.",
+ match.getVersionlessNamespaceURI(), is(NO_VERSION_A_URI));
+ assertThat("Wrong extracted version.",
+ match.getVersion(), is(NO_VERSION_VERSION_DEFAULT));
+ }
+
+ /**
+ * Tests whether the pattern match yields the correct results for an URI with no version part
+ * and a given version format. When there is no versioning information and the format is '{0}',
+ * the versionless URI, the version and the given URI should be the same.
+ */
+ @Test
+ public void matchNoVersionCorrectURIGivenVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(NO_VERSION_PATTERN, NO_VERSION_FORMAT);
+ final ProfileNamespaceURIPatternMatchResult match = pattern.match(NO_VERSION_A_URI);
+
+ assertThat("Pattern should have matched.", match.hasMatched());
+ assertThat("Matched namespace URI should be equal to given namesapce URI.",
+ match.getNamespaceURI(), is(NO_VERSION_A_URI));
+ assertThat("Wrong extracted versionless namespace URI.",
+ match.getVersionlessNamespaceURI(), is(NO_VERSION_A_URI));
+ assertThat("Wrong extracted version.",
+ match.getVersion(), is(NO_VERSION_A_URI));
+ }
+
+ // single version matching behavior
+
+ /**
+ * Tests whether the pattern match yields the correct results for an URI with a single version part
+ * and the default version format.
+ */
+ @Test
+ public void matchSingleVersionCorrectURIDefaultVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(SINGLE_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternMatchResult match = pattern.match(SINGLE_VERSION_A7_URI);
+
+ assertThat("Pattern should have matched.", match.hasMatched());
+ assertThat("Matched namespace URI should be equal to given namesapce URI.",
+ match.getNamespaceURI(), is(SINGLE_VERSION_A7_URI));
+ assertThat("Wrong extracted versionless namespace URI.",
+ match.getVersionlessNamespaceURI(), is(SINGLE_VERSION_A7_VERSIONLESS_URI));
+ assertThat("Wrong extracted version.",
+ match.getVersion(), is(SINGLE_VERSION_A7_VERSION_DEFAULT));
+ }
+
+ /**
+ * Tests whether the pattern match yields the correct results for an URI with a single version part
+ * and a given version format.
+ */
+ @Test
+ public void matchSingleVersionCorrectURIGivenVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(SINGLE_VERSION_PATTERN, SINGLE_VERSION_FORMAT);
+ final ProfileNamespaceURIPatternMatchResult match = pattern.match(SINGLE_VERSION_A7_URI);
+
+ assertThat("Pattern should have matched.", match.hasMatched());
+ assertThat("Matched namespace URI should be equal to given namesapce URI.",
+ match.getNamespaceURI(), is(SINGLE_VERSION_A7_URI));
+ assertThat("Wrong extracted versionless namespace URI.",
+ match.getVersionlessNamespaceURI(), is(SINGLE_VERSION_A7_VERSIONLESS_URI));
+ assertThat("Wrong extracted version.",
+ match.getVersion(), is(SINGLE_VERSION_A7_VERSION_FORMAT));
+ }
+
+ // multiple version matching behavior
+
+ /**
+ * Tests whether the pattern match yields the correct results for an URI with a multiple version parts
+ * and the default version format.
+ */
+ @Test
+ public void matchMultipleVersionCorrectURIDefaultVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(MULTI_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternMatchResult match = pattern.match(MULTI_VERSION_A7_701_URI);
+
+ assertThat("Pattern should have matched.", match.hasMatched());
+ assertThat("Matched namespace URI should be equal to given namesapce URI.",
+ match.getNamespaceURI(), is(MULTI_VERSION_A7_701_URI));
+ assertThat("Wrong extracted versionless namespace URI.",
+ match.getVersionlessNamespaceURI(), is(MULTI_VERSION_A7_701_VERSIONLESS_URI));
+ assertThat("Wrong extracted version.",
+ match.getVersion(), is(MULTI_VERSION_A7_701_VERSION_DEFAULT));
+ }
+
+ /**
+ * Tests whether the pattern match yields the correct results for an URI with a multiple version parts
+ * and a given version format.
+ */
+ @Test
+ public void matchMultipleVersionCorrectURIGivenVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(MULTI_VERSION_PATTERN, MULTI_VERSION_FORMAT);
+ final ProfileNamespaceURIPatternMatchResult match = pattern.match(MULTI_VERSION_A7_701_URI);
+
+ assertThat("Pattern should have matched.", match.hasMatched());
+ assertThat("Matched namespace URI should be equal to given namesapce URI.",
+ match.getNamespaceURI(), is(MULTI_VERSION_A7_701_URI));
+ assertThat("Wrong extracted versionless namespace URI.",
+ match.getVersionlessNamespaceURI(), is(MULTI_VERSION_A7_701_VERSIONLESS_URI));
+ assertThat("Wrong extracted version.",
+ match.getVersion(), is(MULTI_VERSION_A7_701_VERSION_FORMAT));
+ }
+
+ // no match behavior
+
+ /**
+ * Tests whether the pattern match yields the correct results for an URI that does not match the pattern.
+ * The namespace URI, the versionless namespace URI and the version should be null.
+ */
+ @Test
+ public void matchCorrectNoMatchBehavior() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(NON_MATCHING_PATTERN);
+ final ProfileNamespaceURIPatternMatchResult match = pattern.match(MULTI_VERSION_A7_701_URI);
+
+ assertThat("Pattern should not have matched.", !match.hasMatched());
+ assertThat("Unmatched URI should yield null namespace URI.",
+ match.getNamespaceURI(), nullValue());
+ assertThat("Unmatched versionless URI should be null.",
+ match.getVersionlessNamespaceURI(), nullValue());
+ assertThat("Unmatched version should be null.",
+ match.getVersion(), nullValue());
+ }
+
+ /**
+ * Tests whether the pattern match yields the correct results for the NO_MATCH constant.
+ * The namespace URI, the versionless namespace URI and the version should be null.
+ */
+ @Test
+ public void matchCorrectNoMatchConstantBehavior() {
+ final ProfileNamespaceURIPatternMatchResult match = ProfileNamespaceURIPatternMatchResult.NO_MATCH;
+
+ assertThat("Pattern should not have matched.", !match.hasMatched());
+ assertThat("Unmatched URI should yield null namespace URI.",
+ match.getNamespaceURI(), nullValue());
+ assertThat("Unmatched versionless URI should be null.",
+ match.getVersionlessNamespaceURI(), nullValue());
+ assertThat("Unmatched version should be null.",
+ match.getVersion(), nullValue());
+ }
+
+ // no version comparison behavior
+
+ /**
+ * Tests whether the comparison between two identical URIs with no version part yields the expected,
+ * equal result.
+ */
+ @Test
+ public void compareNoVersionSameURI() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(NO_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(NO_VERSION_A_URI, NO_VERSION_A_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Same URI should be equal to itself (namespace URI).", comparison.isEqualNamespaceURI());
+ assertThat("Same URI should be equal to itself (versionless URI).", comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Same URI should be equal to itself (version).", comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison between two different URIs with no version part yields the expected,
+ * result.
+ */
+ @Test
+ public void compareNoVersionDifferentURI() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(NO_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(NO_VERSION_A_URI, NO_VERSION_B_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Should not be the same namespace URI.", !comparison.isEqualNamespaceURI());
+ assertThat("Should not be the same versionless URI.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Should be the same version (no version).", comparison.isEqualVersion());
+ }
+
+ // single version comparison behavior
+
+ /**
+ * Tests whether the comparison between two identical URIs with a single version part yields the expected,
+ * equal result.
+ */
+ @Test
+ public void compareSingleVersionSameURISameVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(SINGLE_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(SINGLE_VERSION_A7_URI, SINGLE_VERSION_A7_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Same URI should be equal to itself (namespace URI).", comparison.isEqualNamespaceURI());
+ assertThat("Same URI should be equal to itself (versionless URI).", comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Same URI should be equal to itself (version).", comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison between two versionless URI-equal but version-different URIs with a single version
+ * part yields the expected result.
+ */
+ @Test
+ public void compareSingleVersionSameURIDifferentVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(SINGLE_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(SINGLE_VERSION_A7_URI, SINGLE_VERSION_A8_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Should be different namespace URI.", !comparison.isEqualNamespaceURI());
+ assertThat("Should be the same versionless URI.", comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Should be different versions (7 and 8).", !comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison between two versionless URI-different but version-equal URIs with a single version
+ * part yields the expected result.
+ */
+ @Test
+ public void compareSingleVersionDifferentURISameVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(SINGLE_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(SINGLE_VERSION_A7_URI, SINGLE_VERSION_B7_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Should be different namespace URI.", !comparison.isEqualNamespaceURI());
+ assertThat("Should be different versionless URI.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Should be the same version (7 and 7).", comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison between two versionless URI-different and version-different URIs with a single version
+ * part yields the expected result.
+ */
+ @Test
+ public void compareSingleVersionDifferentURIDifferentVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(SINGLE_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(SINGLE_VERSION_A8_URI, SINGLE_VERSION_B7_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Should be different namespace URI.", !comparison.isEqualNamespaceURI());
+ assertThat("Should be different versionless URI.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Should be different versions (8 and 7).", !comparison.isEqualVersion());
+ }
+
+ // multiple version comparison behavior
+
+ /**
+ * Tests whether the comparison between two identical URIs with multiple version parts yields the expected,
+ * equal result.
+ */
+ @Test
+ public void compareMultiVersionSameURISameVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(MULTI_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(MULTI_VERSION_A7_701_URI, MULTI_VERSION_A7_701_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Same URI should be equal to itself (namespace URI).", comparison.isEqualNamespaceURI());
+ assertThat("Same URI should be equal to itself (versionless URI).", comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Same URI should be equal to itself (version).", comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison between two versionless URI-equal but version-different URIs with multiple version
+ * parts yields the expected result.
+ */
+ @Test
+ public void compareMultiVersionSameURIDifferentVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(MULTI_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(MULTI_VERSION_A7_701_URI, MULTI_VERSION_A7_702_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Should be different namespace URI.", !comparison.isEqualNamespaceURI());
+ assertThat("Should be the same versionless URI.", comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Should be different versions (7,7.0.1 and 7,7.0.2).", !comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison between two versionless URI-different but version-equal URIs with multiple version
+ * parts yields the expected result.
+ */
+ @Test
+ public void compareMultiVersionDifferentURISameVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(MULTI_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(MULTI_VERSION_A7_701_URI, MULTI_VERSION_B7_701_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Should be different namespace URI.", !comparison.isEqualNamespaceURI());
+ assertThat("Should be different versionless URI.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Should be the same version (7,7.0.1 and 7,7.0.1).", comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison between two versionless URI-different and version-different URIs with multiple version
+ * parts yields the expected result.
+ */
+ @Test
+ public void compareMultiVersionDifferentURIDifferentVersion() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(MULTI_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(MULTI_VERSION_A7_702_URI, MULTI_VERSION_B7_701_URI);
+
+ assertThat("Comparison should be valid.", comparison.isValid());
+ assertThat("Should be different namespace URI.", !comparison.isEqualNamespaceURI());
+ assertThat("Should be the same versionless URI.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Should be the same version (7,7.0.2 and 7,7.0.1).", !comparison.isEqualVersion());
+ }
+
+
+ // invalid comparison behavior
+
+ /**
+ * Tests whether the comparison of two non-matching URIs yields the expected, invalid results.
+ */
+ @Test
+ public void compareCorrectInvalidComparisonBehaviorWrongPattern() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(NON_MATCHING_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(SINGLE_VERSION_A7_URI, SINGLE_VERSION_A7_URI);
+
+ assertThat("Comparison should not be valid.", !comparison.isValid());
+ assertThat("Namespace URIs should not be equal due to invalid comparison.", !comparison.isEqualNamespaceURI());
+ assertThat("Versionless URIs should not be equal due to invalid comparison.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Versions should not be equal due to invalid comparison.", !comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison of one non-matching URIs on the left-hand side yields the expected, invalid results.
+ */
+ @Test
+ public void compareCorrectInvalidComparisonBehaviorWrongLHS() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(SINGLE_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(SINGLE_VERSION_NONMATCHING_URI, SINGLE_VERSION_A7_URI);
+
+ assertThat("Comparison should not be valid.", !comparison.isValid());
+ assertThat("Namespace URIs should not be equal due to invalid comparison.", !comparison.isEqualNamespaceURI());
+ assertThat("Versionless URIs should not be equal due to invalid comparison.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Versions should not be equal due to invalid comparison.", !comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the comparison of one non-matching URIs on the right-hand side yields the expected, invalid results.
+ */
+ @Test
+ public void compareCorrectInvalidComparisonBehaviorWrongRHS() {
+ final ProfileNamespaceURIPattern pattern = new ProfileNamespaceURIPattern(SINGLE_VERSION_PATTERN);
+ final ProfileNamespaceURIPatternComparison comparison = pattern.compare(SINGLE_VERSION_A7_URI, SINGLE_VERSION_NONMATCHING_URI);
+
+ assertThat("Comparison should not be valid.", !comparison.isValid());
+ assertThat("Namespace URIs should not be equal due to invalid comparison.", !comparison.isEqualNamespaceURI());
+ assertThat("Versionless URIs should not be equal due to invalid comparison.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Versions should not be equal due to invalid comparison.", !comparison.isEqualVersion());
+ }
+
+ /**
+ * Tests whether the INVALID comparison constant yields the expected, invalid results.
+ */
+ @Test
+ public void compareCorrectInvalidComparisonConstantBehavior() {
+ final ProfileNamespaceURIPatternComparison comparison = ProfileNamespaceURIPatternComparison.INVALID;
+
+ assertThat("Comparison should not be valid.", !comparison.isValid());
+ assertThat("Namespace URIs should not be equal due to invalid comparison.", !comparison.isEqualNamespaceURI());
+ assertThat("Versionless URIs should not be equal due to invalid comparison.", !comparison.isEqualVersionlessNamespaceURI());
+ assertThat("Versions should not be equal due to invalid comparison.", !comparison.isEqualVersion());
+ }
+
+ // registry behavior
+
+ /**
+ * Tests whether the extension point provided through the plugin.xml is correctly loaded into the registry.
+ */
+ @Test
+ public void registryExtensionPointRegistered() {
+ ProfileNamespaceURIPatternRegistry registry = ProfileNamespaceURIPatternRegistry.INSTANCE;
+ assertThat("Pattern from extension point should be in registry.",
+ Iterables.any(registry.getProfileNamespaceURIPatterns(), isExtensionPointPattern()));
+ }
+
+ /**
+ * Tests whether the extension point provided through the plugin.xml behaves as expected, i.e., matches a given string.
+ * This is important to ensure that there are no encoding/decoding issues between the strings when loaded from the extension point.
+ */
+ @Test
+ public void registryExtensionPointCorrectMatch() {
+ ProfileNamespaceURIPatternRegistry registry = ProfileNamespaceURIPatternRegistry.INSTANCE;
+ Iterable<ProfileNamespaceURIPattern> registeredPatterns = Iterables.filter(
+ registry.getProfileNamespaceURIPatterns(), isExtensionPointPattern());
+
+ // pattern has only been registered once
+ ProfileNamespaceURIPattern registeredPattern = Iterables.getOnlyElement(registeredPatterns);
+ ProfileNamespaceURIPatternMatchResult match = registeredPattern.match(EXTENSION_POINT_URI);
+
+ assertThat("Pattern should have matched.", match.hasMatched());
+ assertThat("Wrong extracted versionless URI.",
+ match.getVersionlessNamespaceURI(), is(EXTENSION_POINT_VERSIONLESS_URI));
+ assertThat("Wrong extracted version.",
+ match.getVersion(), is(EXTENSION_POINT_VERSION));
+ }
+
+ /**
+ * Tests whether registering and unregistering patterns through the registry API works as expected.
+ * Unregistering a pattern actually removes the pattern from the registry.
+ * Registering a pattern actually adds the pattern to the registry.
+ * Unregistering a non-existing pattern leaves the registry unchanged.
+ */
+ @Test
+ public void registryCorrectUnregisterAndRegister() {
+ ProfileNamespaceURIPatternRegistry registry = ProfileNamespaceURIPatternRegistry.INSTANCE;
+ Iterable<ProfileNamespaceURIPattern> registeredPatterns = Iterables.filter(
+ registry.getProfileNamespaceURIPatterns(), isExtensionPointPattern());
+
+ ProfileNamespaceURIPattern registeredPattern = Iterables.getOnlyElement(registeredPatterns);
+ int originalSize = registry.getProfileNamespaceURIPatterns().size();
+
+ // unregister existing pattern
+ registry.unregister(registeredPattern);
+ assertThat("Registry should have one entry less.",
+ registry.getProfileNamespaceURIPatterns().size(),
+ is(originalSize - 1));
+
+ // register new pattern
+ registry.register(registeredPattern);
+ assertThat("Registry should have all entries.",
+ registry.getProfileNamespaceURIPatterns().size(),
+ is(originalSize));
+
+ // unregister non-existing pattern
+ registry.unregister(new ProfileNamespaceURIPattern("non-existing"));
+ assertThat("Registry should not have lost an entry.",
+ registry.getProfileNamespaceURIPatterns().size(),
+ is(originalSize));
+ }
+}
diff --git a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/tests/AllTests.java b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/tests/AllTests.java
index 6eb70b151cc..5dedb7e08c4 100644
--- a/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/tests/AllTests.java
+++ b/tests/junit/plugins/uml/org.eclipse.papyrus.uml.modelrepair.tests/src/org/eclipse/papyrus/uml/modelrepair/tests/AllTests.java
@@ -9,6 +9,7 @@
* Contributors:
* Christian W. Damus (CEA) - Initial API and implementation
* Christian W. Damus - bug 485220
+ * Martin Fleck - bug 496307
*
*/
package org.eclipse.papyrus.uml.modelrepair.tests;
@@ -17,6 +18,7 @@ import org.eclipse.papyrus.junit.framework.classification.ClassificationSuite;
import org.eclipse.papyrus.junit.framework.runner.Headless;
import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.StereotypeApplicationRepairSnippetTest;
import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.StereotypeRepairRegressionTest;
+import org.eclipse.papyrus.uml.modelrepair.internal.uripattern.ProfileNamespaceURIPatternTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
@@ -26,7 +28,8 @@ import org.junit.runners.Suite.SuiteClasses;
*/
@Headless
@RunWith(ClassificationSuite.class)
-@SuiteClasses({ StereotypeApplicationRepairSnippetTest.class, StereotypeRepairRegressionTest.class })
+@SuiteClasses({ StereotypeApplicationRepairSnippetTest.class, StereotypeRepairRegressionTest.class,
+ ProfileNamespaceURIPatternTest.class })
public class AllTests {
// JUnit 4 Test Suite
}

Back to the top