EMFTVM compatibility launcher.
diff --git a/plugins/org.eclipse.m2m.atl.emftvm.launcher/META-INF/MANIFEST.MF b/plugins/org.eclipse.m2m.atl.emftvm.launcher/META-INF/MANIFEST.MF
index 48722ea..04ac23b 100644
--- a/plugins/org.eclipse.m2m.atl.emftvm.launcher/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.m2m.atl.emftvm.launcher/META-INF/MANIFEST.MF
@@ -19,4 +19,6 @@
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Bundle-ActivationPolicy: lazy
 Export-Package: org.eclipse.m2m.atl.emftvm.launcher,
- org.eclipse.m2m.atl.emftvm.launcher.debug
+ org.eclipse.m2m.atl.emftvm.launcher.compat,
+ org.eclipse.m2m.atl.emftvm.launcher.debug,
+ org.eclipse.m2m.atl.emftvm.launcher.profiler
diff --git a/plugins/org.eclipse.m2m.atl.emftvm.launcher/plugin.xml b/plugins/org.eclipse.m2m.atl.emftvm.launcher/plugin.xml
index d71753f..93d5bd6 100644
--- a/plugins/org.eclipse.m2m.atl.emftvm.launcher/plugin.xml
+++ b/plugins/org.eclipse.m2m.atl.emftvm.launcher/plugin.xml
@@ -37,4 +37,27 @@
       </launchConfigurationTypeImage>
    </extension>
 
+   <extension
+         point="org.eclipse.m2m.atl.core.launcher">
+      <launcher
+            class="org.eclipse.m2m.atl.emftvm.launcher.compat.EMFTVMUILauncher"
+            name="EMFTVM (Compatibility)">          
+         <option
+               description="Print execution times to console"
+               mode="run"
+               name="printExecutionTime"></option>
+         <option
+               description="Allow inter-model references"
+               name="allowInterModelReferences"></option>
+         <option
+               description="Disable JIT compiler"
+               name="disableJit"></option>
+         <option
+               description="Disassembly mode"
+               mode="debug"
+               name="disassemblyMode">
+         </option>
+      </launcher>
+   </extension>
+
 </plugin>
diff --git a/plugins/org.eclipse.m2m.atl.emftvm.launcher/src/org/eclipse/m2m/atl/emftvm/launcher/compat/EMFTVMUILauncher.java b/plugins/org.eclipse.m2m.atl.emftvm.launcher/src/org/eclipse/m2m/atl/emftvm/launcher/compat/EMFTVMUILauncher.java
new file mode 100644
index 0000000..d837cab
--- /dev/null
+++ b/plugins/org.eclipse.m2m.atl.emftvm.launcher/src/org/eclipse/m2m/atl/emftvm/launcher/compat/EMFTVMUILauncher.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Dennis Wagelaar.
+ * 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:
+ *     Dennis Wagelaar - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.atl.emftvm.launcher.compat;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.m2m.atl.common.ATLLaunchConstants;
+import org.eclipse.m2m.atl.emftvm.launcher.debug.NetworkDebugger;
+import org.eclipse.m2m.atl.emftvm.util.VMException;
+
+/**
+ * The EMFTVM UI extension of the {@link EMFTVMLauncher}, which supports debug.
+ * 
+ * @author <a href="mailto:dwagelaar@gmail.com">Dennis Wagelaar</a>
+ */
+public class EMFTVMUILauncher extends EMFTVMLauncher {
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.emftvm.launcher.compat.EMFTVMLauncher#launch(java.lang.String,
+	 *      org.eclipse.core.runtime.IProgressMonitor, java.util.Map,
+	 *      java.lang.Object[])
+	 */
+	@Override
+	public Object launch(final String mode, final IProgressMonitor monitor, final Map<String, Object> options,
+			final Object... modules) {
+		try {
+			if (mode.equals(ILaunchManager.DEBUG_MODE)) {
+				final ILaunch launch = (ILaunch) options.get("launch");
+				return internalLaunch(new NetworkDebugger(launch, getPort(launch), true), monitor, options, modules); // $NON-NLS-1$
+			} else {
+				return internalLaunch(null, monitor, options, modules);
+			}
+		} catch (CoreException e) {
+			throw new VMException(null, e.getLocalizedMessage(), e);
+		}
+	}
+
+	private int getPort(ILaunch launch) throws CoreException {
+		String portOption = ""; //$NON-NLS-1$
+		if (launch != null) {
+			portOption = launch.getLaunchConfiguration().getAttribute(ATLLaunchConstants.PORT,
+					Integer.valueOf(ATLLaunchConstants.DEFAULT_PORT).toString());
+		}
+		if (portOption.equals("")) { //$NON-NLS-1$
+			portOption = Integer.valueOf(ATLLaunchConstants.DEFAULT_PORT).toString();
+		}
+		return new Integer(portOption).intValue();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#getModes()
+	 */
+	@Override
+	public String[] getModes() {
+		return new String[] { RUN_MODE, DEBUG_MODE };
+	}
+
+}
diff --git a/plugins/org.eclipse.m2m.atl.emftvm/META-INF/MANIFEST.MF b/plugins/org.eclipse.m2m.atl.emftvm/META-INF/MANIFEST.MF
index 660532d..4b655f1 100644
--- a/plugins/org.eclipse.m2m.atl.emftvm/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.m2m.atl.emftvm/META-INF/MANIFEST.MF
@@ -13,14 +13,16 @@
  org.eclipse.m2m.atl.emftvm.impl,
  org.eclipse.m2m.atl.emftvm.impl.resource,
  org.eclipse.m2m.atl.emftvm.jit,
+ org.eclipse.m2m.atl.emftvm.launcher.compat,
  org.eclipse.m2m.atl.emftvm.profiler,
  org.eclipse.m2m.atl.emftvm.util
 Require-Bundle: org.eclipse.core.runtime,
  org.eclipse.emf.ecore;bundle-version="2.4.0";visibility:=reexport,
- org.eclipse.emf.ecore.xmi;bundle-version="2.4.0",
+ org.eclipse.emf.ecore.xmi;bundle-version="2.4.0";visibility:=reexport,
  org.eclipse.m2m.atl.emftvm.trace;visibility:=reexport,
  org.eclipse.m2m.atl.common,
  org.eclipse.core.resources,
  org.eclipse.emf.validation;bundle-version="1.4.0",
- org.objectweb.asm;bundle-version="[5.0.1,6.0.0)"
+ org.objectweb.asm;bundle-version="[5.0.1,6.0.0)",
+ org.eclipse.m2m.atl.core.emf;visibility:=reexport
 Bundle-ActivationPolicy: lazy
diff --git a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/Messages.java b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/Messages.java
new file mode 100644
index 0000000..3143042
--- /dev/null
+++ b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/Messages.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Dennis Wagelaar.
+ * 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:
+ *     Dennis Wagelaar
+ *******************************************************************************/
+package org.eclipse.m2m.atl.emftvm;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Utility class to access externalized Strings for EMFTVM.
+ * 
+ * @author <a href="mailto:dwagelaar@gmail.com">Dennis Wagelaar</a>
+ */
+public final class Messages {
+
+	/** Full qualified path to the properties file in which to seek the keys. */
+	private static final String BUNDLE_NAME = "org.eclipse.m2m.atl.emftvm.messages"; //$NON-NLS-1$
+
+	/** Contains the locale specific {@link String}s needed by this plug-in. */
+	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+
+	/**
+	 * Utility classes don't need to (and shouldn't) be instantiated.
+	 */
+	private Messages() {
+	}
+
+	/**
+	 * Returns a specified {@link String} from the resource bundle.
+	 * 
+	 * @param key
+	 *            Key of the String we seek.
+	 * @return The String from the resource bundle associated with <code>key</code>.
+	 */
+	public static String getString(String key) {
+		try {
+			return RESOURCE_BUNDLE.getString(key);
+		} catch (MissingResourceException e) {
+			return '!' + key + '!';
+		}
+	}
+
+	/**
+	 * Returns a String from the resource bundle binded with the given arguments.
+	 * 
+	 * @param key
+	 *            Key of the String we seek.
+	 * @param arguments
+	 *            Arguments for the String formatting.
+	 * @return formatted {@link String}.
+	 * @see MessageFormat#format(String, Object...)
+	 */
+	public static String getString(String key, Object... arguments) {
+		if (arguments == null) {
+			return getString(key);
+		}
+		return MessageFormat.format(getString(key), arguments);
+	}
+}
diff --git a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/launcher/compat/EMFTVMLauncher.java b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/launcher/compat/EMFTVMLauncher.java
new file mode 100644
index 0000000..c253293
--- /dev/null
+++ b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/launcher/compat/EMFTVMLauncher.java
@@ -0,0 +1,325 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Dennis Wagelaar.
+ * 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:
+ *     Dennis Wagelaar - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.m2m.atl.emftvm.launcher.compat;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.m2m.atl.common.ATLLogger;
+import org.eclipse.m2m.atl.core.IModel;
+import org.eclipse.m2m.atl.core.IReferenceModel;
+import org.eclipse.m2m.atl.core.emf.EMFModel;
+import org.eclipse.m2m.atl.core.emf.EMFReferenceModel;
+import org.eclipse.m2m.atl.core.launch.ILauncher;
+import org.eclipse.m2m.atl.core.service.LauncherService;
+import org.eclipse.m2m.atl.emftvm.EmftvmFactory;
+import org.eclipse.m2m.atl.emftvm.ExecEnv;
+import org.eclipse.m2m.atl.emftvm.Messages;
+import org.eclipse.m2m.atl.emftvm.Metamodel;
+import org.eclipse.m2m.atl.emftvm.Model;
+import org.eclipse.m2m.atl.emftvm.Module;
+import org.eclipse.m2m.atl.emftvm.util.DefaultModuleResolver;
+import org.eclipse.m2m.atl.emftvm.util.EMFTVMUtil;
+import org.eclipse.m2m.atl.emftvm.util.ModuleNotFoundException;
+import org.eclipse.m2m.atl.emftvm.util.ModuleResolver;
+import org.eclipse.m2m.atl.emftvm.util.TimingData;
+import org.eclipse.m2m.atl.emftvm.util.VMException;
+import org.eclipse.m2m.atl.emftvm.util.VMMonitor;
+
+/**
+ * The EMFVM implementation of the {@link ILauncher} interface.
+ * 
+ * @author <a href="mailto:dwagelaar@gmail.com">Dennis Wagelaar</a>
+ */
+public class EMFTVMLauncher implements ILauncher {
+
+	/** The {@link ILauncher} extension name. */
+	public static final String LAUNCHER_NAME = "EMFTVM (Compatibility)"; //$NON-NLS-1$
+
+	/** The Default model factory name to use. */
+	public static final String MODEL_FACTORY_NAME = "EMF"; //$NON-NLS-1$
+
+	private static final String EMF_URI_PREFIX = "emftvm://"; //$NON-NLS-1$
+
+	protected Map<String, IModel> models;
+
+	protected Map<String, Module> libraries;
+
+	protected ResourceSet moduleResourceSet;
+
+	protected ModuleResolver moduleResolver;
+
+	protected ExecEnv execEnv;
+
+	protected TimingData timingData;
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public String getName() {
+		return LAUNCHER_NAME;
+	}
+
+	/**
+	 * Adds any model to the local map.
+	 * 
+	 * @param model
+	 *            the {@link IModel}
+	 * @param name
+	 *            the model name
+	 * @param referenceModelName
+	 *            the model reference model name
+	 */
+	protected void addModel(IModel model, String name, String referenceModelName) {
+		if (models.containsKey(name)) {
+			ATLLogger.warning(Messages.getString("EMFTVMLauncher.MODEL_REGISTERED", name)); //$NON-NLS-1$
+		} else {
+			models.put(name, model);
+		}
+		if (!models.containsKey(referenceModelName)) {
+			models.put(referenceModelName, model.getReferenceModel());
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#addInModel(org.eclipse.m2m.atl.core.IModel,
+	 *      java.lang.String, java.lang.String)
+	 */
+	public void addInModel(IModel model, String name, String referenceModelName) {
+		model.setIsTarget(false);
+		addModel(model, name, referenceModelName);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#addInOutModel(org.eclipse.m2m.atl.core.IModel,
+	 *      java.lang.String, java.lang.String)
+	 */
+	public void addInOutModel(IModel model, String name, String referenceModelName) {
+		model.setIsTarget(true);
+		addModel(model, name, referenceModelName);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#addOutModel(org.eclipse.m2m.atl.core.IModel,
+	 *      java.lang.String, java.lang.String)
+	 */
+	public void addOutModel(IModel model, String name, String referenceModelName) {
+		model.setIsTarget(true);
+		addModel(model, name, referenceModelName);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#addLibrary(java.lang.String,
+	 *      java.lang.Object)
+	 */
+	public void addLibrary(String name, Object library) {
+		if (libraries.containsKey(name)) {
+			ATLLogger.warning(Messages.getString("EMFTVMLauncher.LIBRARY_REGISTERED", name)); //$NON-NLS-1$
+		} else {
+			libraries.put(name, getModuleFromObject(library));
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#initialize(java.util.Map)
+	 */
+	public void initialize(Map<String, Object> parameters) {
+		models = new HashMap<String, IModel>();
+		libraries = new HashMap<String, Module>();
+		moduleResourceSet = new ResourceSetImpl();
+		moduleResolver = new DefaultModuleResolver(EMF_URI_PREFIX, moduleResourceSet);
+		execEnv = EmftvmFactory.eINSTANCE.createExecEnv();
+		timingData = new TimingData();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#launch(java.lang.String,
+	 *      org.eclipse.core.runtime.IProgressMonitor, java.util.Map,
+	 *      java.lang.Object[])
+	 */
+	public Object launch(final String mode, final IProgressMonitor monitor, final Map<String, Object> options,
+			final Object... modules) {
+		return internalLaunch(null, monitor, options, modules);
+	}
+
+	/**
+	 * Launches the transformation with preloaded modules.
+	 * 
+	 * @param tool
+	 *            the execution tool
+	 * @param monitor
+	 *            the progression monitor
+	 * @param options
+	 *            the launching options
+	 * @param modules
+	 *            the transformation modules
+	 * @return the execution result
+	 */
+	protected Object internalLaunch(final VMMonitor tool, final IProgressMonitor monitor,
+			final Map<String, Object> options, Object... modules) {
+		getModuleFromObject(modules[0]);
+		for (int i = 1; i < modules.length; i++) {
+			getModuleFromObject(modules[i]);
+		}
+
+		for (Map.Entry<String, IModel> entry : models.entrySet()) {
+			String name = entry.getKey();
+			IModel iModel = entry.getValue();
+			if (iModel instanceof IReferenceModel) {
+				Metamodel metamodel = EmftvmFactory.eINSTANCE.createMetamodel();
+				metamodel.setResource(((EMFReferenceModel) iModel).getResource());
+				execEnv.registerMetaModel(name, metamodel);
+			} else {
+				Model model = EmftvmFactory.eINSTANCE.createModel();
+				model.setResource(((EMFModel) iModel).getResource());
+				if (iModel.isTarget()) {
+					model.setAllowInterModelReferences(
+							LauncherService.getBooleanOption(options.get("allowInterModelReferences"), false)); //$NON-NLS-1$
+					execEnv.registerOutputModel(name, model);
+				} else {
+					execEnv.registerInputModel(name, model);
+				}
+			}
+		}
+
+		execEnv.setMonitor(tool);
+		execEnv.setJitDisabled(LauncherService.getBooleanOption(options.get("jitDisabled"), false)); //$NON-NLS-1$
+		final Object result = execEnv.run(timingData);
+
+		if (LauncherService.getBooleanOption(options.get("printExecutionTime"), false)) { //$NON-NLS-1$
+			ATLLogger.info(timingData.toString());
+		}
+		return result;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#loadModule(java.io.InputStream)
+	 */
+	public Module loadModule(final InputStream inputStream) {
+		final Resource resource = moduleResourceSet
+				.createResource(URI.createURI(UUID.randomUUID().toString() + DefaultModuleResolver.FILE_EXT));
+		try {
+			resource.load(inputStream, Collections.emptyMap());
+			final Module module = findModule(resource);
+			final Matcher matcher = EMFTVMUtil.DELIM_PATTERN.matcher(module.getName());
+			final String path = matcher.replaceAll("/");
+			resource.setURI(URI.createURI(EMF_URI_PREFIX + path + DefaultModuleResolver.FILE_EXT));
+			execEnv.loadModule(moduleResolver, module.getName());
+			return module;
+		} catch (IOException e) {
+			throw new VMException(null, e.getLocalizedMessage(), e);
+		}
+	}
+
+	/**
+	 * Load a module if necessary.
+	 * 
+	 * @param module
+	 *            the given {@link Module} or {@link InputStream}.
+	 * @return the {@link Module}
+	 */
+	protected Module getModuleFromObject(Object module) {
+		if (module instanceof InputStream) {
+			return loadModule((InputStream) module);
+		} else if (module instanceof Module) {
+			return (Module) module;
+		}
+		return null;
+	}
+
+	/**
+	 * Finds the first module in {@link Resource}
+	 * 
+	 * <pre>
+	 * r
+	 * </pre>
+	 * 
+	 * .
+	 * 
+	 * @param r
+	 * @return the module with the given name inside
+	 * 
+	 *         <pre>
+	 *         r
+	 *         </pre>
+	 * 
+	 *         , or <code>null</code>
+	 */
+	private Module findModule(final Resource r) throws ModuleNotFoundException {
+		for (EObject o : r.getContents()) {
+			if (o instanceof Module) {
+				return (Module) o;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#getModel(java.lang.String)
+	 */
+	public IModel getModel(String modelName) {
+		return models.get(modelName);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#getLibrary(java.lang.String)
+	 */
+	public Object getLibrary(String libraryName) {
+		return libraries.get(libraryName);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#getDefaultModelFactoryName()
+	 */
+	public String getDefaultModelFactoryName() {
+		return MODEL_FACTORY_NAME;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * @see org.eclipse.m2m.atl.core.launch.ILauncher#getModes()
+	 */
+	public String[] getModes() {
+		return new String[] { RUN_MODE };
+	}
+}
diff --git a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/messages.properties b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/messages.properties
new file mode 100644
index 0000000..5eef175
--- /dev/null
+++ b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/messages.properties
@@ -0,0 +1,12 @@
+################################################################################
+# Copyright (c) 2017 Dennis Wagelaar.
+# 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:
+#     Dennis Wagelaar
+################################################################################
+EMFTVMLauncher.LIBRARY_REGISTERED=Library {0} has already been registered
+EMFTVMLauncher.MODEL_REGISTERED=Model {0} has already been registered