Bug 474577 - Register migration factory for all versions using wildcards

Modified *emf.edapt.factories extension point to consider wildcards in
the nsURI during the factory registration.

Change-Id: I9edb1e1c86a69de747487b86a49b0aab3e92e644
Signed-off-by: Alexandra Buzila <abuzila@eclipsesource.com>
[implementation]
Signed-off-by: Johannes Faltermeier <jfaltermeier@eclipsesource.com>
[test integration in build]
diff --git a/plugins/org.eclipse.emf.edapt.migration/schema/org.eclipse.emf.edapt.factories.exsd b/plugins/org.eclipse.emf.edapt.migration/schema/org.eclipse.emf.edapt.factories.exsd
index 1801e29..0690176 100644
--- a/plugins/org.eclipse.emf.edapt.migration/schema/org.eclipse.emf.edapt.factories.exsd
+++ b/plugins/org.eclipse.emf.edapt.migration/schema/org.eclipse.emf.edapt.factories.exsd
@@ -66,6 +66,14 @@
                </appInfo>
             </annotation>
          </attribute>
+         <attribute name="useWildcards" type="boolean" use="default" value="false">
+            <annotation>
+               <documentation>
+                  Defines whether wildcards in the nsURI should be considered. When this option is set to true, any URIs that match the value declared in the nsURI field will be taken into account. WIldcards should be specified using the &lt;b&gt;*&lt;/b&gt; character. 
+&lt;p&gt;Example: http://www.example.com/sampleuri*
+               </documentation>
+            </annotation>
+         </attribute>
       </complexType>
    </element>
 
diff --git a/plugins/org.eclipse.emf.edapt.migration/src/org/eclipse/emf/edapt/internal/migration/internal/FactoryHelper.java b/plugins/org.eclipse.emf.edapt.migration/src/org/eclipse/emf/edapt/internal/migration/internal/FactoryHelper.java
index e6e4c08..a748faa 100644
--- a/plugins/org.eclipse.emf.edapt.migration/src/org/eclipse/emf/edapt/internal/migration/internal/FactoryHelper.java
+++ b/plugins/org.eclipse.emf.edapt.migration/src/org/eclipse/emf/edapt/internal/migration/internal/FactoryHelper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 BMW Car IT, Technische Universitaet Muenchen, and others.
+ * Copyright (c) 2007, 2016 BMW Car IT, Technische Universitaet Muenchen, 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
@@ -11,6 +11,7 @@
 package org.eclipse.emf.edapt.internal.migration.internal;
 
 import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -37,12 +38,15 @@
 
 	private static final String CLASS = "class"; //$NON-NLS-1$
 	private static final String NS_URI = "nsURI"; //$NON-NLS-1$
+	private static final String USE_WILDCARDS = "useWildcards"; //$NON-NLS-1$
 	private static final String POINT_ID = "org.eclipse.emf.edapt.factories"; //$NON-NLS-1$
 
 	private final Map<String, Class<? extends EFactory>> nsURIToFactoryMap;
+	private final Map<String, Boolean> wildcardsUsageMap;
 
 	private FactoryHelper() {
 		nsURIToFactoryMap = new LinkedHashMap<String, Class<? extends EFactory>>();
+		wildcardsUsageMap = new HashMap<String, Boolean>();
 		readExtensionPoint();
 	}
 
@@ -68,7 +72,9 @@
 			if (nsURI == null || clazz == null) {
 				return;
 			}
+			final boolean useWildcards = Boolean.parseBoolean(configurationElement.getAttribute(USE_WILDCARDS));
 			nsURIToFactoryMap.put(nsURI, clazz);
+			wildcardsUsageMap.put(nsURI, useWildcards);
 		} catch (final ClassNotFoundException e) {
 			MigrationPlugin.INSTANCE.log(e);
 		}
@@ -93,11 +99,10 @@
 	 */
 	public void overrideFactory(EPackage ePackage) {
 		try {
-			if (!nsURIToFactoryMap.containsKey(ePackage.getNsURI())) {
+			final Class<? extends EFactory> clazz = getEFactoryFromMap(ePackage.getNsURI());
+			if (clazz == null) {
 				return;
 			}
-			final Class<? extends EFactory> clazz = nsURIToFactoryMap.get(ePackage
-				.getNsURI());
 			final EFactory eFactory = clazz.getConstructor().newInstance();
 			ePackage.setEFactoryInstance(eFactory);
 		} catch (final InstantiationException e) {
@@ -114,4 +119,33 @@
 			MigrationPlugin.INSTANCE.log(e);
 		}
 	}
+
+	/**
+	 * Returns the {@link EFactory} registered for the given nsURI, taking wildcards into account, if such a factory
+	 * exists.
+	 *
+	 * @param nsURI
+	 * @return if there exists a factory registered for a matching nsURI, without any wildcards, it will be returned
+	 *         first. Otherwise, the method will return the first factory that it can match (using wildcards) to the
+	 *         given nsURI
+	 *         May return null.
+	 */
+	private Class<? extends EFactory> getEFactoryFromMap(String nsURI) {
+		if (nsURI == null) {
+			return null;
+		}
+		// if we have an exact match, that doesn't use wildcards, return the value from the factory map
+		if (wildcardsUsageMap.get(nsURI) != null && !wildcardsUsageMap.get(nsURI)) {
+			return nsURIToFactoryMap.get(nsURI);
+		}
+		// else, search if we can find a match using wildcards
+		// if multiple matches exist, the first one will be returned
+		for (final String uri : wildcardsUsageMap.keySet()) {
+			if (wildcardsUsageMap.get(uri) && nsURI.matches(uri.replace("*", ".*"))) { //$NON-NLS-1$ //$NON-NLS-2$
+				return nsURIToFactoryMap.get(uri);
+			}
+		}
+		// fallback to factory map
+		return nsURIToFactoryMap.get(nsURI);
+	}
 }
diff --git a/tests/org.eclipse.emf.edapt.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.emf.edapt.tests/META-INF/MANIFEST.MF
index d8281f2..4b571c1 100644
--- a/tests/org.eclipse.emf.edapt.tests/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.emf.edapt.tests/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
-Bundle-SymbolicName: org.eclipse.emf.edapt.tests
+Bundle-SymbolicName: org.eclipse.emf.edapt.tests;singleton:=true
 Bundle-Version: 1.2.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Require-Bundle: org.eclipse.emf.ecore.xmi;bundle-version="[2.9.1,3.0.0)",
diff --git a/tests/org.eclipse.emf.edapt.tests/build.properties b/tests/org.eclipse.emf.edapt.tests/build.properties
index ed58c4e..f14697c 100644
--- a/tests/org.eclipse.emf.edapt.tests/build.properties
+++ b/tests/org.eclipse.emf.edapt.tests/build.properties
@@ -14,4 +14,5 @@
 bin.includes = META-INF/,\
                .,\
                plugin.properties,\
-               archive/
+               archive/,\
+               plugin.xml
diff --git a/tests/org.eclipse.emf.edapt.tests/plugin.xml b/tests/org.eclipse.emf.edapt.tests/plugin.xml
new file mode 100644
index 0000000..7a5814c
--- /dev/null
+++ b/tests/org.eclipse.emf.edapt.tests/plugin.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension
+         point="org.eclipse.emf.edapt.factories">
+      <factory
+            class="org.eclipse.emf.edapt.tests.migration.FactoryHelperTestEFactory1"
+            nsURI="org.eclipse.emf.edapt.tests.factory1*"
+            useWildcards="true">
+      </factory>
+      <factory
+            class="org.eclipse.emf.edapt.tests.migration.FactoryHelperTestEFactory2"
+            nsURI="org.eclipse.emf.edapt.tests.factory1"
+            useWildcards="false">
+      </factory>
+   </extension>
+
+</plugin>
diff --git a/tests/org.eclipse.emf.edapt.tests/pom.xml b/tests/org.eclipse.emf.edapt.tests/pom.xml
index 1386e23..b6f3475 100644
--- a/tests/org.eclipse.emf.edapt.tests/pom.xml
+++ b/tests/org.eclipse.emf.edapt.tests/pom.xml
@@ -11,7 +11,7 @@
 	</parent>
 	<groupId>edapt</groupId>
 	<artifactId>org.eclipse.emf.edapt.tests</artifactId>
-	<packaging>eclipse-plugin</packaging>
+	<packaging>eclipse-test-plugin</packaging>
 
 	<build>
 		<plugins>
@@ -27,6 +27,7 @@
 							<testClassesDirectory>${project.build.outputDirectory}</testClassesDirectory>
 							<excludes>
 								<exclude>**/GMFLifecycleTest.java</exclude>
+								<exclude>**/FactoryHelperTest.java</exclude>
 							</excludes>
 						</configuration>
 						<goals>
@@ -35,6 +36,18 @@
 					</execution>
 				</executions>
 			</plugin>
+			<plugin>
+				<groupId>org.eclipse.tycho</groupId>
+				<artifactId>tycho-surefire-plugin</artifactId>
+				<version>${tycho-version}</version>
+				<configuration>
+					<useUIHarness>true</useUIHarness>
+					<useUIThread>true</useUIThread>
+					<includes>
+						<include>**/FactoryHelperTest.java</include>
+					</includes>
+				</configuration>
+			</plugin>
 		</plugins>
 	</build>
 	<dependencies>
diff --git a/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTest.java b/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTest.java
new file mode 100644
index 0000000..a833cfb
--- /dev/null
+++ b/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTest.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2007-2016 BMW Car IT, TUM, EclipseSource Muenchen 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:
+ * Alexandra Buzila - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.edapt.tests.migration;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.emf.ecore.EFactory;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EcoreFactory;
+import org.eclipse.emf.edapt.internal.migration.internal.FactoryHelper;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for the FactoryHelper.
+ *
+ * @author Alexandra Buzila
+ */
+@SuppressWarnings({ "restriction", "nls" })
+public class FactoryHelperTest {
+	private final String NSURI_NO_WILDCARDS = "org.eclipse.emf.edapt.tests.factory1";
+	private final String NSURI_WITH_WILDCARDS = "org.eclipse.emf.edapt.tests.factory1*";
+	private final String NSURI_NO_FACTORY = "org.eclipse.emf.edapt.tests.nofactory";
+	private static EPackage ePackage;
+	private EFactory initialFactory;
+
+	@Before
+	public void setup() {
+		ePackage = EcoreFactory.eINSTANCE.createEPackage();
+		ePackage.setName("testPackage");
+		ePackage.setNsPrefix("test");
+		initialFactory = EcoreFactory.eINSTANCE.createEFactory();
+		ePackage.setEFactoryInstance(initialFactory);
+	}
+
+	@Test
+	public void testOverrideFactoryNoRegistration() {
+		ePackage.setNsURI(NSURI_NO_FACTORY);
+
+		FactoryHelper.INSTANCE.overrideFactory(ePackage);
+		final EFactory eFactoryInstance = ePackage.getEFactoryInstance();
+		// no factory should be registered for the given URI, so the package must have the initial factory
+		assertTrue(eFactoryInstance == initialFactory);
+	}
+
+	@Test
+	public void testRegisterFactoryWithWildcards() {
+		ePackage.setNsURI(NSURI_WITH_WILDCARDS + "1234");
+
+		FactoryHelper.INSTANCE.overrideFactory(ePackage);
+		final EFactory eFactoryInstance = ePackage.getEFactoryInstance();
+		assertFalse(eFactoryInstance == initialFactory);
+		assertTrue(eFactoryInstance instanceof FactoryHelperTestEFactory1);
+	}
+
+	@Test
+	public void testRegisterFactoryWithoutWildcards() {
+		ePackage.setNsURI(NSURI_NO_WILDCARDS);
+
+		FactoryHelper.INSTANCE.overrideFactory(ePackage);
+		final EFactory eFactoryInstance = ePackage.getEFactoryInstance();
+		assertFalse(eFactoryInstance == initialFactory);
+		assertTrue(eFactoryInstance instanceof FactoryHelperTestEFactory2);
+	}
+
+}
diff --git a/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTestEFactory1.java b/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTestEFactory1.java
new file mode 100644
index 0000000..fd71d4d
--- /dev/null
+++ b/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTestEFactory1.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2007-2016 BMW Car IT, TUM, EclipseSource Muenchen 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:
+ * Alexandra Buzila - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.edapt.tests.migration;
+
+import org.eclipse.emf.ecore.impl.EFactoryImpl;
+
+/**
+ * Test EFactory for the FactoryHelperTest.
+ * 
+ * @author Alexandra Buzila
+ *
+ */
+public class FactoryHelperTestEFactory1 extends EFactoryImpl {
+
+}
\ No newline at end of file
diff --git a/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTestEFactory2.java b/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTestEFactory2.java
new file mode 100644
index 0000000..c83b95f
--- /dev/null
+++ b/tests/org.eclipse.emf.edapt.tests/src/org/eclipse/emf/edapt/tests/migration/FactoryHelperTestEFactory2.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2007-2016 BMW Car IT, TUM, EclipseSource Muenchen 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:
+ * Alexandra Buzila - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.edapt.tests.migration;
+
+import org.eclipse.emf.ecore.impl.EFactoryImpl;
+
+/**
+ * Test EFactory for the FactoryHelperTest.
+ *
+ * @author Alexandra Buzila
+ *
+ */
+public class FactoryHelperTestEFactory2 extends EFactoryImpl {
+
+}
\ No newline at end of file