CQ-4081: Initial import
diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/.classpath b/bundles/org.eclipse.e4.core.deeplink.handler/.classpath
new file mode 100644
index 0000000..8a8f166
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<classpath>

+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>

+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>

+	<classpathentry kind="src" path="src"/>

+	<classpathentry kind="output" path="bin"/>

+</classpath>

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/.project b/bundles/org.eclipse.e4.core.deeplink.handler/.project
new file mode 100644
index 0000000..e48608f
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<projectDescription>

+	<name>org.eclipse.e4.core.deeplink.handler</name>

+	<comment></comment>

+	<projects>

+	</projects>

+	<buildSpec>

+		<buildCommand>

+			<name>org.eclipse.jdt.core.javabuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.ManifestBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.SchemaBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+	</buildSpec>

+	<natures>

+		<nature>org.eclipse.pde.PluginNature</nature>

+		<nature>org.eclipse.jdt.core.javanature</nature>

+	</natures>

+</projectDescription>

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.e4.core.deeplink.handler/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..e60562e
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Mon Dec 21 14:06:00 CST 2009

+eclipse.preferences.version=1

+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5

+org.eclipse.jdt.core.compiler.compliance=1.5

+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error

+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error

+org.eclipse.jdt.core.compiler.source=1.5

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.core.deeplink.handler/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..eace3fb
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Handler Plug-in
+Bundle-SymbolicName: org.eclipse.e4.core.deeplink.handler;singleton:=true
+Bundle-Version: 4.6.0.qualifier
+Bundle-Activator: org.eclipse.e4.core.deeplink.api.Activator
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.osgi.services;bundle-version="3.1.200",
+ javax.servlet;bundle-version="2.4.0",
+ javax.servlet.jsp;bundle-version="2.0.0",
+ org.eclipse.equinox.http.registry;bundle-version="1.0.100",
+ org.eclipse.equinox.http.servlet;bundle-version="1.0.100",
+ org.eclipse.equinox.http.jetty;bundle-version="1.1.0",
+ org.mortbay.jetty.server,
+ org.eclipse.core.resources,
+ org.eclipse.e4.core.functionalprog;bundle-version="1.0.0",
+ org.apache.commons.lang;bundle-version="2.3.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.e4.core.deeplink.api;uses:="org.eclipse.e4.core.deeplink.handler,javax.servlet.http"
diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/about.html b/bundles/org.eclipse.e4.core.deeplink.handler/about.html
new file mode 100644
index 0000000..f77f378
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/about.html
@@ -0,0 +1,22 @@
+<h1>About This Content</h1>
+
+23 June, 2010
+
+<h2>License</h2>
+
+<p>The Eclipse Foundation makes available all content in this plug-in
+("Content"). Unless otherwise indicated below, the Content is provided
+to you under the terms and conditions of the Eclipse Public License
+Version 1.0 ("EPL"). A copy of the EPL is available at
+http://www.eclipse.org/legal/epl-v10.html. For purposes of the EPL,
+"Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse
+Foundation, the Content is being redistributed by another party
+("Redistributor") and different terms and conditions may apply to your
+use of any object code in the Content. Check the Redistributor’s
+license that was provided with the Content. If no such license exists,
+contact the Redistributor. Unless otherwise indicated below, the terms
+and conditions of the EPL still apply to any source code in the
+Content and such source code may be obtained at
+http://www.eclipse.org.</p>
diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/build.properties b/bundles/org.eclipse.e4.core.deeplink.handler/build.properties
new file mode 100644
index 0000000..6f20375
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/build.properties
@@ -0,0 +1,5 @@
+source.. = src/

+output.. = bin/

+bin.includes = META-INF/,\

+               .,\

+               plugin.xml

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/plugin.xml b/bundles/org.eclipse.e4.core.deeplink.handler/plugin.xml
new file mode 100644
index 0000000..9a663a1
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/plugin.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<?eclipse version="3.4"?>

+<plugin>

+   <extension-point id="deepLinkTypeHandler" name="Deep Link Type Handler" schema="schema/deepLinkTypeHander.exsd"/>

+

+</plugin>

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/schema/deepLinkTypeHander.exsd b/bundles/org.eclipse.e4.core.deeplink.handler/schema/deepLinkTypeHander.exsd
new file mode 100644
index 0000000..e2eddfb
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/schema/deepLinkTypeHander.exsd
@@ -0,0 +1,112 @@
+<?xml version='1.0' encoding='UTF-8'?>

+<!-- Schema file written by PDE -->

+<schema targetNamespace="org.eclipse.e4.enterprise.deeplink.deeplink.handler" xmlns="http://www.w3.org/2001/XMLSchema">

+<annotation>

+      <appinfo>

+         <meta.schema plugin="org.eclipse.e4.enterprise.deeplink.deeplink.handler" id="deepLinkTypeHandler" name="Deep Link Type Handler"/>

+      </appinfo>

+      <documentation>

+         [Enter description of this extension point.]

+      </documentation>

+   </annotation>

+

+   <element name="extension">

+      <annotation>

+         <appinfo>

+            <meta.element />

+         </appinfo>

+         <documentation>

+            A deep link typeHandler allows the developer to extend the set of deep link URLs.

+         </documentation>

+      </annotation>

+      <complexType>

+         <sequence minOccurs="1" maxOccurs="unbounded">

+            <element ref="typeHandler"/>

+         </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="typeHandler">

+      <complexType>

+         <attribute name="name" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+         <attribute name="class" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+               <appinfo>

+                  <meta.attribute kind="java" basedOn="org.eclipse.e4.core.deeplink.api.AbstractDeepLinkTypeHandler:"/>

+               </appinfo>

+            </annotation>

+         </attribute>

+      </complexType>

+   </element>

+

+   <annotation>

+      <appinfo>

+         <meta.section type="since"/>

+      </appinfo>

+      <documentation>

+         [Enter the first release in which this extension point appears.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appinfo>

+         <meta.section type="examples"/>

+      </appinfo>

+      <documentation>

+         [Enter extension point usage example here.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appinfo>

+         <meta.section type="apiinfo"/>

+      </appinfo>

+      <documentation>

+         [Enter API information here.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appinfo>

+         <meta.section type="implementation"/>

+      </appinfo>

+      <documentation>

+         [Enter information about supplied implementation of this extension point.]

+      </documentation>

+   </annotation>

+

+

+</schema>

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/AbstractDeepLinkInstanceHandler.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/AbstractDeepLinkInstanceHandler.java
new file mode 100644
index 0000000..e6894f6
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/AbstractDeepLinkInstanceHandler.java
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.api;

+

+import java.util.Map;

+

+import org.eclipse.core.runtime.ILog;

+import org.eclipse.core.runtime.IStatus;

+import org.eclipse.core.runtime.Status;

+

+/**

+ * This class defines the abstract behavior for all deeplink-addressable objects

+ * that define method callbacks.

+ */

+public abstract class AbstractDeepLinkInstanceHandler {

+

+	/**

+	 * Activate a deeplink callback on this object.

+	 * <p>

+	 * 

+	 * @param handlerInstanceID

+	 *            The application instance (or RCP container) that this deeplink

+	 *            currently is living in.

+	 * @param action

+	 *            the "action" or verb part of the URL or an empty string if

+	 *            none.

+	 * @param params

+	 *            Any deeplink parameters specified as a part of the URL.

+	 * @return A Map<String, String> containing any arbitrary results.

+	 */

+	public abstract Map<String, String> activate(String handlerInstanceID, String action, Map<String, String[]> params);

+

+	/**

+	 * Execute the application-specified handler for the URL

+	 * 

+	 * @param results

+	 * @throws LinkFailureException

+	 */

+	public void handle(final ParameterProcessResults[] results, final String handlerInstanceId, final String action, final Map<String, String[]> params) {

+		debug("Command received: " + handlerInstanceId);

+		debug("Running action for app: " + handlerInstanceId);

+		try {

+			results[0].outputData = activate(handlerInstanceId, action , params);

+			results[0].activatedParameterCallback = true;

+		} catch (Throwable t) {

+			error(handlerInstanceId);

+			rethrowException(t);

+		}

+	}

+

+	protected IStatus status(int severity, String message) {

+		return new Status(severity, Activator.PLUGIN_ID, message);

+	}

+

+	protected void error(String message) {

+		getLog().log(status(Status.ERROR, message));

+	}

+

+	protected void info(String message) {

+		getLog().log(status(Status.INFO, message));

+	}

+

+	protected void debug(String message) {

+		getLog().log(status(Status.WARNING, message));

+	}

+

+	private ILog getLog() {

+		return Activator.getDefault().getLog();

+	}

+

+	private void rethrowException(Throwable terminatingException) {

+		if (terminatingException != null) {

+			if (!(terminatingException instanceof RuntimeException)) {

+				throw new RuntimeException(terminatingException);

+			}

+			throw (RuntimeException) terminatingException;

+		}

+	}

+

+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/AbstractDeepLinkTypeHandler.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/AbstractDeepLinkTypeHandler.java
new file mode 100644
index 0000000..b228243
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/AbstractDeepLinkTypeHandler.java
@@ -0,0 +1,171 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.api;

+

+import static org.eclipse.e4.core.functionalprog.optionmonad.None.none;
+import static org.eclipse.e4.core.functionalprog.optionmonad.Some.some;
+

+import static org.apache.commons.lang.StringEscapeUtils.escapeXml;

+

+import java.io.IOException;

+import java.io.UnsupportedEncodingException;

+import java.util.Map;

+

+import javax.servlet.ServletOutputStream;

+import javax.servlet.http.HttpServletRequest;

+import javax.servlet.http.HttpServletResponse;

+

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IConfigurationElement;

+import org.eclipse.core.runtime.IExtensionRegistry;

+import org.eclipse.core.runtime.Platform;

+import org.eclipse.core.runtime.Status;

+import org.eclipse.e4.core.functionalprog.optionmonad.Option;
+

+/**

+ * Given the following archetypal deeplink:

+ * <ul>

+ * <li>deeplink://appInstance/handlerType/handlerInstanceId/action?param1=value1&param2=value2...

+ * </ul>

+ * A DeepLinkTypeHandler is a strategy pattern object that defines how deeplink

+ * requests are handled for a particular deeplink handlerType.

+ * <p>

+ * Each DeepLinkTypeHandler must be registered with the system via the

+ * deepLinkTypeHandler extension point.

+ * <p>

+ * This is (more or less) following a Servlet Delegate pattern.   

+ * This knows about HTTP stuff (req/resp etc) and should not leak this info to 

+ * subclasses or collaborators.

+ */

+public abstract class AbstractDeepLinkTypeHandler {

+

+	public static final String CLASS = "class";

+	private HttpServletRequest request;

+	private HttpServletResponse response;

+

+	private URLPathInfoParser parsedPathParts;

+

+	public IStatusFactory statusFactory = new StatusFactory();

+

+	public void init(HttpServletRequest request, HttpServletResponse response, URLPathInfoParser pathParts) {

+		try {

+			request.setCharacterEncoding("UTF-8");

+		} catch (UnsupportedEncodingException e) {

+			throw new RuntimeException(e);

+		}

+		response.setContentType("text/xml");

+		this.request = request;

+		this.response = response;

+		this.parsedPathParts = pathParts;

+	}

+

+	public abstract void processDeepLink() throws IOException;

+	

+	public void doGet() throws IOException{

+		processDeepLink();

+	}

+

+	public void doPost() throws IOException{

+		processDeepLink();

+	}

+

+

+	private Option<IConfigurationElement> find(IConfigurationElement[] elementsToLookIn, String idToFind) {

+		for (IConfigurationElement configurationElement : elementsToLookIn) {

+			String id = configurationElement.getAttribute(idToFind);

+			if (getHandlerId().equals(id)) {

+				return some(configurationElement);

+			}

+		}

+		return none();

+	}

+

+	@SuppressWarnings("unchecked")

+	protected Map<String, String[]> getParameterMap() {

+		return request.getParameterMap();

+	}

+

+	protected String getHandlerType() {

+		return parsedPathParts.handlerType;

+	}

+

+	protected String getHandlerId() {

+		return parsedPathParts.handlerId;

+	}

+

+	protected String getAction() {

+		return parsedPathParts.action.getOrSubstitute("");

+	}

+

+	/*

+	 * FIXME DJO/JADN 2010-02-20. This method is monolithic, thus does not lend

+	 * itself to being modified either here or by subclasses eg if the "value"

+	 * [from results.outputData.get(key)] needs anything other than .toString()

+	 * then you are in trouble.

+	 */

+	protected void outputResponse(final ParameterProcessResults results) throws IOException {

+		ServletOutputStream out = response.getOutputStream();

+		out.println("<?xml version=\"1.0\"?>");

+		out.println("<deeplink>");

+		out.println("   <result id=\"" + parsedPathParts.handlerId + "\" loaded=\"" + results.loaded + "\" callbackRan=\"" + results.activatedParameterCallback + "\"/>");

+		if (results.activatedParameterCallback) {

+			out.println("   <outputData id=\"" + parsedPathParts.handlerId + "\">");

+			if (results.outputData != null) {

+				for (String key : results.outputData.keySet()) {

+					String value = escapeXml(results.outputData.get(key));

+					out.print("      <element key=\"" + key + "\">");

+					out.print(value);

+					out.println("</element>");

+				}

+			}

+			out.println("   </outputData>");

+		}

+		out.println("</deeplink>");

+	}

+

+	protected IConfigurationElement[] getCongfigElementsFromRegistry(String pluginId, String extPointID) {

+		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();

+		return extensionRegistry.getConfigurationElementsFor(pluginId, extPointID);

+	}

+

+	protected void findInstanceHandlerAndExecuteCallback(ParameterProcessResults[] results, IConfigurationElement[] congfigElementsFromRegistry, Map<String, String[]> parameters, String extensionPointID) {

+		Option<IConfigurationElement> found = find(congfigElementsFromRegistry, extensionPointID);

+		if (found.hasValue()) {

+			IConfigurationElement configurationElement = found.get();

+			Option<AbstractDeepLinkInstanceHandler> instanceHandlerOption = buildInstanceHandlerFromClassAttribute(configurationElement);

+			if (instanceHandlerOption.hasValue()) {

+				AbstractDeepLinkInstanceHandler instanceHandler = instanceHandlerOption.get();

+				instanceHandler.handle(results, getHandlerId(), getAction(), parameters);

+			}

+		}

+	}

+

+	private Option<AbstractDeepLinkInstanceHandler> buildInstanceHandlerFromClassAttribute(IConfigurationElement configurationElement) {

+		try {

+			Object interimObject = configurationElement.createExecutableExtension(CLASS);

+			if (interimObject instanceof AbstractDeepLinkInstanceHandler) {

+				AbstractDeepLinkInstanceHandler handler = (AbstractDeepLinkInstanceHandler) interimObject;

+				return some(handler);

+			} else {

+				Activator.getDefault().getLog().log(new Status(Status.INFO, Activator.PLUGIN_ID, ("Found extension point but not DeepLinkInstanceHandler: " + configurationElement.getName())));

+				return none();

+			}

+		} catch (CoreException e) {

+			logExtensionError(configurationElement.getName(), e);

+			return none();

+		}

+	}

+

+	private void logExtensionError(String name, CoreException e) {

+		Activator.getDefault().getLog().log(new Status(Status.ERROR, Activator.PLUGIN_ID, ("Incorrect extension for: " + name), e));

+	}

+

+}

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/Activator.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/Activator.java
new file mode 100644
index 0000000..bd1f533
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/Activator.java
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.api;

+

+import org.eclipse.core.runtime.Plugin;

+import org.eclipse.e4.core.deeplink.handler.HttpServiceTracker;
+import org.eclipse.equinox.http.registry.HttpContextExtensionService;

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.ServiceReference;

+import org.osgi.util.tracker.ServiceTracker;

+

+

+/**

+ * The activator class controls the plug-in life cycle

+ */

+public class Activator extends Plugin {

+

+	// The plug-in ID

+	public static final String PLUGIN_ID = "org.eclipse.e4.core.deeplink.handler";

+	public static final String DEEP_LINK_EXT_PT_ID = "deepLinkTypeHandler";

+

+	// The shared instance

+	private static Activator plugin;

+

+	protected HttpServiceTracker httpServiceTracker;

+	

+	/**

+	 * The constructor

+	 */

+	public Activator() {

+		plugin=this;

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)

+	 */

+	public void start(BundleContext context) throws Exception {

+		super.start(context);

+

+        // RAP [fappel]: ensure that the rap http context was loaded before

+        //               the mapping of servlets from branding takes place

+        String serviceName = HttpContextExtensionService.class.getName();

+        ServiceTracker httpContextExtensionServiceTracker

+          = new ServiceTracker( context, serviceName, null )

+        {

+          public Object addingService( final ServiceReference reference ) {

+            Object result = super.addingService( reference );

+            httpServiceTracker = new HttpServiceTracker(context);

+            httpServiceTracker.open();

+            return result;

+          }

+        };

+        httpContextExtensionServiceTracker.open();

+//		/*

+//		 * DO NOT RUN ANY OTHER CODE AFTER THIS LINE.  If you do, then you are

+//		 * likely to cause a deadlock in class loader code.  Please see Bug 86450

+//		 * for more information.

+//		 */

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)

+	 */

+	public void stop(BundleContext context) throws Exception {

+		plugin = null;

+		super.stop(context);

+	}

+

+	/**

+	 * Returns the shared instance

+	 *

+	 * @return the shared instance

+	 */

+	public static Activator getDefault() {

+		return plugin;

+	}

+

+}

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/IStatusFactory.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/IStatusFactory.java
new file mode 100644
index 0000000..adee0d8
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/IStatusFactory.java
@@ -0,0 +1,31 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.api;

+

+import org.eclipse.core.runtime.IStatus;

+

+/**

+ * A abstraction for injecting specific IStatus objects into an implementation

+ * for testability purposes.  It smells, but there doesn't seem to be an easier

+ * way to make this code testable since Eclipse's Status doesn't implement

+ * equals/hashCode (as-of 3.4).

+ */

+public interface IStatusFactory {

+

+	public IStatus error(String message);

+

+	public IStatus error(String message, Throwable t);

+

+	public IStatus warning(String message);

+

+	public IStatus info(String message);

+

+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/ParameterProcessResults.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/ParameterProcessResults.java
new file mode 100644
index 0000000..858de5b
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/ParameterProcessResults.java
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+/**

+ * 

+ */

+package org.eclipse.e4.core.deeplink.api;

+

+import java.util.Map;

+

+/**

+ * A data transfer object (since Java can't return multiple values from a 

+ * function) encapsulating the result of executing a deeplink.

+ */

+public class ParameterProcessResults {

+	public boolean loaded = false;

+	public boolean activatedParameterCallback = false;

+	public Map<String, String> outputData = null;

+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/StatusFactory.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/StatusFactory.java
new file mode 100644
index 0000000..1348ebd
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/StatusFactory.java
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.api;

+

+import org.eclipse.core.runtime.IStatus;

+import org.eclipse.core.runtime.Status;

+

+

+/**

+ * A abstraction for injecting specific IStatus objects into an implementation

+ * for testability purposes.  It smells, but there doesn't seem to be an easier

+ * way to make this code testable since Eclipse's Status doesn't implement

+ * equals/hashCode (as-of 3.4).

+ */

+public class StatusFactory implements IStatusFactory {

+

+	public IStatus error(String message) {

+		return new Status(Status.ERROR, Activator.PLUGIN_ID, message);

+	}

+

+	public IStatus error(String message, Throwable t) {

+		return new Status(Status.ERROR, Activator.PLUGIN_ID, message, t);

+	}

+	

+	public IStatus warning(String message) {

+		return new Status(Status.WARNING, Activator.PLUGIN_ID, message);

+	}

+

+	public IStatus info(String message) {

+		return new Status(Status.INFO, Activator.PLUGIN_ID, message);

+	}

+

+}

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/URLPathInfoParser.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/URLPathInfoParser.java
new file mode 100644
index 0000000..23bc155
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/api/URLPathInfoParser.java
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.api;

+

+import org.eclipse.e4.core.functionalprog.optionmonad.Option;
+

+import static org.eclipse.e4.core.functionalprog.optionmonad.None.none;
+import static org.eclipse.e4.core.functionalprog.optionmonad.Some.some;
+

+/**

+ * Archetypal deeplink:

+ * deeplink://appInstance/handlerType/handlerInstanceId/action?param1=value1&param2=value2...

+ * 

+ * Example:

+ * deeplink://myApp/perspective/org.eclipse.myApp.myPerspectiveID/do-stuff?animal=monkey&colour=blue&mood=angry

+ *

+ */

+public class URLPathInfoParser {

+	public final String handlerType;

+	public final String handlerId;

+	public final Option<String> action;

+

+	public URLPathInfoParser(String urlPathInfo) {

+		if (urlPathInfo == null || "/".equals(urlPathInfo)) {

+			throw new IllegalArgumentException("Empty URL path: nothing to do");

+		}

+		

+		String[] urlParts = urlPathInfo.split("/+");

+		if (urlParts.length < 3) {

+			throw new IllegalArgumentException("Need both of: '/handlerType/handlerInstanceId' in URL but got: " + urlPathInfo);

+		}

+		handlerType = urlParts[1];

+		handlerId = urlParts[2];

+		if (urlParts.length > 3) {

+			action = some(urlParts[3]);

+		} else {

+			action = none();

+		}

+	}

+	

+	@Override

+	public String toString() {

+		return handlerType + "/" + handlerId + (action.hasValue() ? "/" + action.get() : "");

+	}

+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/DeepLinkTypeHandlerFactory.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/DeepLinkTypeHandlerFactory.java
new file mode 100644
index 0000000..2fbfc73
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/DeepLinkTypeHandlerFactory.java
@@ -0,0 +1,59 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.handler;

+

+import static org.eclipse.e4.core.functionalprog.optionmonad.None.none;
+import static org.eclipse.e4.core.functionalprog.optionmonad.Some.some;
+

+import java.util.Map;

+

+import javax.servlet.http.HttpServletRequest;

+import javax.servlet.http.HttpServletResponse;

+

+import org.eclipse.e4.core.deeplink.api.AbstractDeepLinkTypeHandler;
+import org.eclipse.e4.core.deeplink.api.URLPathInfoParser;
+import org.eclipse.e4.core.functionalprog.optionmonad.Option;
+

+/**

+ * (non-API) class DeepLinkTypeHandlerFactory.

+ * <p>

+ * Given the following archetypal deeplink:

+ * <ul>

+ * <li>deeplink://appInstance/handlerType/handlerInstanceId/action?param1=value1&param2=value2...

+ * </ul>

+ * A DeepLinkTypeHandler is a strategy pattern object that defines how deeplink

+ * requests are handled for a particular deeplink handlerType.

+ * <p>

+ * This class is a factory for retrieving a type handler for a particular handlerType. 

+ */

+public class DeepLinkTypeHandlerFactory {

+	

+	private Map<String, AbstractDeepLinkTypeHandler> handlers = null;

+	

+	public DeepLinkTypeHandlerFactory(Map<String, AbstractDeepLinkTypeHandler> typeHandlerMap) {

+		handlers = typeHandlerMap;

+	}

+

+	public Option<AbstractDeepLinkTypeHandler> createTypeHandler(HttpServletRequest request,

+			HttpServletResponse response) {

+

+		URLPathInfoParser pathParts = new URLPathInfoParser(request.getPathInfo());

+

+		AbstractDeepLinkTypeHandler typeHandler = handlers.get(pathParts.handlerType);

+		if (typeHandler != null ) {

+			typeHandler.init(request, response, pathParts);

+			return some(typeHandler);

+		} else {

+			return none();

+		}

+	}

+

+}

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/DeepLinkTypeHandlerMapper.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/DeepLinkTypeHandlerMapper.java
new file mode 100644
index 0000000..9c6f167
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/DeepLinkTypeHandlerMapper.java
@@ -0,0 +1,58 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.handler;

+

+import java.util.HashMap;

+import java.util.Map;

+

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IConfigurationElement;

+import org.eclipse.core.runtime.IExtensionRegistry;

+import org.eclipse.core.runtime.Status;

+import org.eclipse.e4.core.deeplink.api.AbstractDeepLinkTypeHandler;
+import org.eclipse.e4.core.deeplink.api.Activator;
+

+

+/**

+ * A function object that computes a Map linking the handlerType identifiers

+ * to instances of {@link AbstractDeepLinkTypeHandler} using the extension 

+ * point registry.

+ */

+public class DeepLinkTypeHandlerMapper {

+	

+	Map<String, AbstractDeepLinkTypeHandler> handlerMap = new HashMap<String, AbstractDeepLinkTypeHandler>();

+	

+	public DeepLinkTypeHandlerMapper(IExtensionRegistry extensionRegistry) {

+		if(extensionRegistry == null) {

+			throw new IllegalArgumentException("IExtensionResgistry passed to DeepLinkTypeHandlerMapper was null");

+		}

+		

+		IConfigurationElement[] elements = extensionRegistry.getConfigurationElementsFor(Activator.PLUGIN_ID,

+						Activator.DEEP_LINK_EXT_PT_ID);

+		

+		for (IConfigurationElement element : elements) {

+			String name = element.getAttribute("name");

+			try {

+				AbstractDeepLinkTypeHandler handler = (AbstractDeepLinkTypeHandler) element.createExecutableExtension("class");

+				handlerMap.put(name, handler);

+			} catch (CoreException e) {

+				Activator.getDefault().getLog().log(

+						new Status(Status.ERROR, Activator.PLUGIN_ID, "Incorrect deep link extension for: " + name, e));

+				continue;

+			}

+		}

+	}

+

+	public Map<String, AbstractDeepLinkTypeHandler> getMap() {

+		return handlerMap;

+	}

+

+}

diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/HttpServiceTracker.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/HttpServiceTracker.java
new file mode 100644
index 0000000..9640f41
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/HttpServiceTracker.java
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.handler;

+

+import java.text.MessageFormat;

+import java.util.ArrayList;

+import java.util.Iterator;

+import java.util.List;

+

+import org.eclipse.core.runtime.IStatus;

+import org.eclipse.core.runtime.Status;

+import org.eclipse.e4.core.deeplink.api.Activator;
+import org.eclipse.equinox.http.registry.HttpContextExtensionService;

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.ServiceReference;

+import org.osgi.service.http.HttpContext;

+import org.osgi.service.http.HttpService;

+import org.osgi.util.tracker.ServiceTracker;

+

+

+/**

+ * An OSGI service tracker that registers the /deeplink servlet context with

+ * the deeplink handler servlet.

+ * <p>

+ * FIXME: Future: Add public API to add (/context, Servlet) pairs?  Extension point?

+ */

+public class HttpServiceTracker extends ServiceTracker {

+	public static final String DEFAULT_SERVLET = "rap";

+	public static final String ID_HTTP_CONTEXT = "org.eclipse.rap.httpcontext";

+

+	private HttpService httpService;

+	private final List<String> servletAliases = new ArrayList<String>();

+

+	public HttpServiceTracker(final BundleContext context) {

+		super(context, HttpService.class.getName(), null);

+		// FIXME: Hard code this for now....

+		servletAliases.add("deeplink");

+	}

+

+	public Object addingService(final ServiceReference reference) {

+		httpService = (HttpService) context.getService(reference);

+		HttpContext obContext = getE4HttpContext(reference);

+

+		if (servletAliases.size() == 0) {

+			// register default servlet

+			servletAliases.add(DEFAULT_SERVLET);

+		}

+		for (Iterator<String> it = servletAliases.iterator(); it.hasNext();) {

+			String name = (String) it.next();

+			try {

+				RequestHandler handler = new RequestHandler();

+				httpService.registerServlet(

+						"/" + name, handler, null, obContext); //$NON-NLS-1$

+			} catch (Exception e) {

+				String text = "Could not register servlet mapping ''{0}''.";

+				Object[] param = new Object[] { name };

+				String msg = MessageFormat.format(text, param);

+				Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID,

+						IStatus.OK, msg, e);

+				Activator.getDefault().getLog().log(status);

+			}

+		}

+		return httpService;

+	}

+

+	private HttpContext getE4HttpContext(final ServiceReference reference) {

+		String name = HttpContextExtensionService.class.getName();

+		ServiceReference serviceRef = context.getServiceReference(name);

+		HttpContextExtensionService service = (HttpContextExtensionService) context

+				.getService(serviceRef);

+		return service.getHttpContext(reference, ID_HTTP_CONTEXT);

+	}

+

+	public void removedService(final ServiceReference reference, final Object service) {

+		for (Iterator<String> iterator = servletAliases.iterator(); iterator

+				.hasNext();) {

+			String name = (String) iterator.next();

+			httpService.unregister("/" + name); //$NON-NLS-1$

+		}

+		super.removedService(reference, service);

+	}

+

+	public void addServletAlias(final String name) {

+		servletAliases.add(name);

+	}

+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/RequestHandler.java b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/RequestHandler.java
new file mode 100644
index 0000000..04ee61d
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.deeplink.handler/src/org/eclipse/e4/core/deeplink/handler/RequestHandler.java
@@ -0,0 +1,144 @@
+/******************************************************************************
+ * Copyright (c) David Orme 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:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.core.deeplink.handler;

+

+import java.io.IOException;

+import java.util.Map;

+

+import javax.servlet.ServletConfig;

+import javax.servlet.ServletException;

+import javax.servlet.ServletOutputStream;

+import javax.servlet.http.HttpServlet;

+import javax.servlet.http.HttpServletRequest;

+import javax.servlet.http.HttpServletResponse;

+

+import org.eclipse.core.runtime.Platform;

+import org.eclipse.core.runtime.Status;

+import org.eclipse.e4.core.deeplink.api.AbstractDeepLinkTypeHandler;
+import org.eclipse.e4.core.deeplink.api.Activator;
+import org.eclipse.e4.core.functionalprog.optionmonad.Option;
+

+

+/**

+ * The deeplink handler servlet.

+ */

+public class RequestHandler extends HttpServlet {

+

+	private static final long serialVersionUID = 1L;

+

+	private static DeepLinkTypeHandlerFactory typeHandlerFactory;

+

+	public RequestHandler() {				

+		DeepLinkTypeHandlerMapper deepLinkTypeHandlerMapper = new DeepLinkTypeHandlerMapper(Platform.getExtensionRegistry());

+		Map<String, AbstractDeepLinkTypeHandler> handlerMap = deepLinkTypeHandlerMapper.getMap();

+		typeHandlerFactory = new DeepLinkTypeHandlerFactory(handlerMap);

+	}

+	

+	// Used to inject mapping dependency for testing

+	RequestHandler(Map<String, AbstractDeepLinkTypeHandler> handlerMap) {

+		typeHandlerFactory = new DeepLinkTypeHandlerFactory(handlerMap);

+	}

+

+	public void init(final ServletConfig config) throws ServletException {

+		super.init(config);

+	}

+

+	@Override

+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)

+			throws ServletException, IOException {

+

+		if( !isRequestFromLocalhost(req) ) {

+			resp.sendError(HttpServletResponse.SC_FORBIDDEN);

+			return;

+		}

+		

+		try {

+			Option<AbstractDeepLinkTypeHandler> typeHandlerOption = typeHandlerFactory.createTypeHandler(req, resp);

+			if (typeHandlerOption.hasValue()) {

+				AbstractDeepLinkTypeHandler typeHandler = typeHandlerOption.get();

+				typeHandler.doGet();			

+			} else {

+				String message = "No deep link handler for URL path: " + req.getPathInfo();

+				logInfo(message);

+				returnErrorMessageToClient(message, resp);

+			}

+		} catch (Throwable t) {

+			logUnhandledExceptionAndReturnResult(t, resp);

+		}

+	}

+

+

+	@Override

+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)

+			throws ServletException, IOException {		

+		

+		if( !isRequestFromLocalhost(req) ) {

+			resp.sendError(HttpServletResponse.SC_FORBIDDEN);

+			return;

+		}

+		

+		try {

+			Option<AbstractDeepLinkTypeHandler> typeHandlerOption = typeHandlerFactory.createTypeHandler(req, resp);

+			if (typeHandlerOption.hasValue()) {

+				AbstractDeepLinkTypeHandler typeHandler = typeHandlerOption.get();

+				typeHandler.doPost();

+			} else {

+				String message = "No deep link handler for URL path: " + req.getPathInfo();

+				logInfo(message);

+				returnErrorMessageToClient(message, resp);

+			}

+		} catch (Throwable t) {

+			logUnhandledExceptionAndReturnResult(t, resp);

+		}

+	}

+

+	private boolean isRequestFromLocalhost(HttpServletRequest req) {

+		String remoteHost = req.getRemoteHost();

+		return "localhost".equalsIgnoreCase(remoteHost) || "127.0.0.1".equalsIgnoreCase(remoteHost);

+	}

+	

+	private void logUnhandledExceptionAndReturnResult(Throwable t, HttpServletResponse response) {

+		returnErrorMessageToClient(t.getMessage(), response);

+		logException("Unhandled exception processing HTTP request: "

+								+ t.getMessage(), t);

+	}

+

+	/**

+	 * FIXME: All result XML generation needs to be centralized in a single

+	 * factory.

+	 */

+	private void returnErrorMessageToClient(String message, HttpServletResponse response) {

+		response.setContentType("text/xml");

+		try {

+			ServletOutputStream out = response.getOutputStream();	

+			out.println("<?xml version=\"1.0\"?>");

+			out.println("<deeplink>");

+			out.println("   <result exception=\"" + message + "\"/>");

+			out.println("</deeplink>");

+		} catch (IOException e) {

+			logException("Unable to return error result to client: " 

+					+ e.getMessage(), e);

+		}

+	}

+

+	private void logException(String message, Throwable t) {

+		Activator.getDefault().getLog().log(

+				new Status(Status.ERROR, Activator.PLUGIN_ID,

+						message, t));

+	}

+	

+	private void logInfo(String message) {

+		Activator.getDefault().getLog().log(

+				new Status(Status.ERROR, Activator.PLUGIN_ID,

+						message));

+	}

+	

+}
\ No newline at end of file