514604: ATL is not current (incompatible with Xtext, Orbit)

Hide ANTLR from the classpath.
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=514604
diff --git a/plugins/org.eclipse.m2m.atl.dsls/.classpath b/plugins/org.eclipse.m2m.atl.dsls/.classpath
index 2fbb7a2..326620b 100644
--- a/plugins/org.eclipse.m2m.atl.dsls/.classpath
+++ b/plugins/org.eclipse.m2m.atl.dsls/.classpath
@@ -3,5 +3,6 @@
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.4"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
 	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="lib" path="lib/org.antlr.runtime_3.0.0.v200803061811.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/plugins/org.eclipse.m2m.atl.dsls/.project b/plugins/org.eclipse.m2m.atl.dsls/.project
index c58ebe9..8456973 100644
--- a/plugins/org.eclipse.m2m.atl.dsls/.project
+++ b/plugins/org.eclipse.m2m.atl.dsls/.project
@@ -22,7 +22,7 @@
 		</buildCommand>
 		<buildCommand>
 			<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
-			<triggers>full,incremental,</triggers>
+			<triggers>full,</triggers>
 			<arguments>
 				<dictionary>
 					<key>LaunchConfigHandle</key>
diff --git a/plugins/org.eclipse.m2m.atl.dsls/META-INF/MANIFEST.MF b/plugins/org.eclipse.m2m.atl.dsls/META-INF/MANIFEST.MF
index 990e65d..25e7552 100644
--- a/plugins/org.eclipse.m2m.atl.dsls/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.m2m.atl.dsls/META-INF/MANIFEST.MF
@@ -14,7 +14,6 @@
  org.eclipse.m2m.atl.dsls.textsource
 Require-Bundle: org.eclipse.core.resources,
  org.eclipse.core.runtime,
- org.antlr.runtime;bundle-version="[3.0.0,3.1.0)",
  org.eclipse.m2m.atl.common,
  org.eclipse.emf.common,
  org.eclipse.m2m.atl.core.emf,
diff --git a/plugins/org.eclipse.m2m.atl.dsls/build.properties b/plugins/org.eclipse.m2m.atl.dsls/build.properties
index 372ef7a..380a231 100644
--- a/plugins/org.eclipse.m2m.atl.dsls/build.properties
+++ b/plugins/org.eclipse.m2m.atl.dsls/build.properties
@@ -6,7 +6,9 @@
                about.html,\
                plugin.properties,\
                resources/,\
-               schema/
+               schema/,\
+               lib/
 src.includes = schema/,\
                resources/,\
                about.html
+jars.extra.classpath = lib/org.antlr.runtime_3.0.0.v200803061811.jar
diff --git a/plugins/org.eclipse.m2m.atl.dsls/src/org/eclipse/m2m/atl/dsls/tcs/injector/ANTLR3ClassLoader.java b/plugins/org.eclipse.m2m.atl.dsls/src/org/eclipse/m2m/atl/dsls/tcs/injector/ANTLR3ClassLoader.java
new file mode 100644
index 0000000..61e41cc
--- /dev/null
+++ b/plugins/org.eclipse.m2m.atl.dsls/src/org/eclipse/m2m/atl/dsls/tcs/injector/ANTLR3ClassLoader.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Willink Transformations 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:
+ *     E.D.Willink - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.atl.dsls.tcs.injector;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.emf.common.EMFPlugin;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.m2m.atl.dsls.Activator;
+import org.eclipse.m2m.atl.dsls.tcs.injector.wrappers.ParserWrapper;
+import org.osgi.framework.Bundle;
+
+/**
+ * The ANTLR3ClassLoader ensures that all ANTLR classes are loaded from the internal ANTLR 3.0.0 library without
+ * regard to any other versions of ANTLR that may be one the classpath.
+ */
+public class ANTLR3ClassLoader extends URLClassLoader
+{
+	private static final String ORG_ANTLR_RUNTIME = "org.antlr.runtime";
+	private static final String ORG_ANTLR_RUNTIME_3_0_0_JAR = "org.antlr.runtime_3.0.0.v200803061811.jar";
+	private static final String ORG_ECLIPSE_M2M_ATL_DSLS_TCS_INJECTOR = ANTLR3ClassLoader.class.getPackage().getName();
+	private static final String ORG_ECLIPSE_M2M_ATL_DSLS_TCS_INJECTOR_WRAPPERS_ANTLR3 = ORG_ECLIPSE_M2M_ATL_DSLS_TCS_INJECTOR + ".wrappers.antlr3";
+	private static final String ORG_ECLIPSE_M2M_ATL_DSLS_TCS_INJECTOR_WRAPPERS_ANTLR3_PARSERWRAPPER = ORG_ECLIPSE_M2M_ATL_DSLS_TCS_INJECTOR_WRAPPERS_ANTLR3 + ".ParserWrapper";
+
+	private static ClassLoader antlrClassLoader = null;
+
+	/**
+	 * Return the ANTLR3 ParserWrapper loading ANTLR3 classes from the local library and other classes from classLoader.
+	 */
+	public static ParserWrapper getParserWrapper(ClassLoader classLoader) throws Exception {
+		if (antlrClassLoader == null) {
+			String locationString;
+			if (EMFPlugin.IS_ECLIPSE_RUNNING) {
+				Bundle bundle = Platform.getBundle(Activator.PLUGIN_ID);
+				locationString = bundle.getLocation();
+				URI locationURI = URI.createURI(locationString);
+				if (locationURI.hasOpaquePart()) {					// Trim the leading reference: or initial@reference:
+					locationString = locationURI.opaquePart() + "bin/";
+				}
+				else {
+					locationString = locationString + "bin/";
+				}
+			}
+			else {
+				String resourceName = ANTLR3ClassLoader.class.getName().replace(".", "/") + ".class";
+				URL url = ANTLR3ClassLoader.class.getClassLoader().getResource(resourceName);
+				locationString = url.toString();
+			}
+			int binIndex = locationString.indexOf("/bin/");
+			URL antlrURL = new URL(locationString.substring(0, binIndex) + "/lib/" + ORG_ANTLR_RUNTIME_3_0_0_JAR);
+			InputStream inputStream = antlrURL.openStream();				// Throws an IOException if local ANTLR library missing avoiding confusing resolution elsewhere
+			inputStream.close();
+			URL localURL = new URL(locationString.substring(0, binIndex+5));
+			antlrClassLoader = new ANTLR3ClassLoader(new URL[] {antlrURL, localURL}, classLoader);
+		}
+		Class parserWrapperClass = antlrClassLoader.loadClass(ORG_ECLIPSE_M2M_ATL_DSLS_TCS_INJECTOR_WRAPPERS_ANTLR3_PARSERWRAPPER);
+		return (ParserWrapper)parserWrapperClass.newInstance();
+	}
+
+	private ClassLoader parent;
+
+	private ANTLR3ClassLoader(URL[] urls, ClassLoader parent) throws MalformedURLException {
+		super(urls, null);
+		this.parent = parent;
+	}
+
+	/**
+	 * ANTLR and all classes that reference ANTLR must use this ClassLoader to avoid 'same' class loaded twice issues.
+	 */
+	public Class loadClass(String name) throws ClassNotFoundException {
+		try {
+			if (name.startsWith(ORG_ANTLR_RUNTIME)) {
+				Class loadClass = super.loadClass(name);
+				// System.out.println("Hit: " + name);
+				return loadClass;
+			}
+			if (name.startsWith(ORG_ECLIPSE_M2M_ATL_DSLS_TCS_INJECTOR_WRAPPERS_ANTLR3)) {
+				Class loadClass = super.loadClass(name);
+				// System.out.println("Hit: " + name);
+				return loadClass;
+			}
+			if (name.startsWith(ORG_ECLIPSE_M2M_ATL_DSLS_TCS_INJECTOR) && name.contains("ANTLR3")) {
+				Class loadClass = super.loadClass(name);
+				// System.out.println("Hit: " + name);
+				return loadClass;
+			}
+		} catch (ClassNotFoundException e) {
+			// System.out.println("Miss: " + name);
+			return parent.loadClass(name);
+		}
+		// System.out.println("Bypass: " + name);
+		return parent.loadClass(name);
+	}
+}
diff --git a/plugins/org.eclipse.m2m.atl.dsls/src/org/eclipse/m2m/atl/dsls/tcs/injector/ParserLauncher.java b/plugins/org.eclipse.m2m.atl.dsls/src/org/eclipse/m2m/atl/dsls/tcs/injector/ParserLauncher.java
index ca5a5a6..a4a27bf 100644
--- a/plugins/org.eclipse.m2m.atl.dsls/src/org/eclipse/m2m/atl/dsls/tcs/injector/ParserLauncher.java
+++ b/plugins/org.eclipse.m2m.atl.dsls/src/org/eclipse/m2m/atl/dsls/tcs/injector/ParserLauncher.java
@@ -61,7 +61,11 @@
 			}
 		} else {
 			// default parser generator
-			parserWrapper = new org.eclipse.m2m.atl.dsls.tcs.injector.wrappers.antlr3.ParserWrapper();
+			try {
+				parserWrapper = ANTLR3ClassLoader.getParserWrapper(getClass().getClassLoader());
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
 		}
 		
 		String nameAndProductionRule = (String)arguments.get("name");