blob: 54adf46da965572c8813821e78c15a2a3a7a588c [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC
"-//Dawid Weiss//DTD DocBook V3.1-Based Extension for XML and graphics inclusion//EN"
"http://www.cs.put.poznan.pl/dweiss/dtd/dweiss-docbook-extensions.dtd"[
<!ENTITY % local SYSTEM "../local-entities.ent">
%local;
]>
<chapter id="deeplink">
<title>Deeplinking - Making an RCP application URL-addressable</title>
<para>Web and networked applications have shown the power and versatility of hyperlinking.
Rich graphical applications have, generally speaking, missed out on the benefits of
hyperlinking: being able to easily connect anything to anything else, across technologies
and platforms.</para>
<sect1>
<title>Why deeplinking?</title>
<para>Now that web browsers are increasingly being embedded into applications and
hyperlinking is being implemented in desktop operating systems, we feel it would be
beneficial if client-side applications could participate on an equal footing with
web applications.</para>
<para>Why?</para>
<para>In order to understand the benefits that this could bring
client-side applications, it is useful to first describe how URLs and hyperlinks
are currently used in web applications:</para>
<sect2>
<title>URLs specify multiple entry points to applications</title>
<para>Web applications commonly use URLs to specify multiple "starting places" within
an application. For example, a content management system may expose separate URLs to
enter the application at the system blog, the wiki, or within the calendaring system:</para>
<para>In contrast, rich client applications have traditionally imposed a
rigid navigational structure on the user, forcing him to start at the same
entry screen and navigate everywhere else from there.</para>
</sect2>
<sect2>
<title>URLs specify the initial information to load into a page</title>
<para>URLs addressing pages within a web application may also include information
about data to load. These "concatinated keys" of application + data identifier then may
be emailed, sent via instant messaging clients, or embedded
in applications and then used by <emphasis>other</emphasis>users to identify
the same content on the same web site later. Common URLs of this sort include:</para>
<itemizedlist>
<listitem>
<para>Google search URLs identifying particular searches/results</para>
</listitem>
<listitem>
<para>URLs identifying SlideShare presentations or YouTube videos</para>
</listitem>
<listitem>
<para>A specific LinkedIn user's home or profile page</para>
</listitem>
<listitem>
<para>Etc...</para>
</listitem>
</itemizedlist>
<para>Applied effectively, this capability provides constant-time navigation to common
bits of data within an application.</para>
<para>In contrast, rich client applications have traditionally imposed a rigid
navigational structure on the user, forcing him to start at the same entry screen
and navigate everywhere else from there.</para>
</sect2>
<sect2>
<title>URLs help break applications into components</title>
<para>While users can reference parts of an application by encoding input parameters
into the URL, application programmers can then use this same capability to break
applications into modules identified by these same entry points.</para>
<para>In Web 1.0, or page-based applications, the entry points are specified by
the set of pages and their URL parameters. This sort of application's API is then defined by
the set of pages it has and the parameters these pages can accept.</para>
<para>In AJAX applications, these modules and entry points
can be made even richer because the result of a request no longer is an HTML page,
but rather is an XML or JSON document. This result document contains the data that is then rendered
into the web client's page via JavaScript and CSS.</para>
<para>The API of this kind of application then
becomes the set of XML or JSON results that can be retrieved by sending
requests with parameters encoded in the query string. This kind of API
then basically becomes a generic remote procedure call with HTTP as the
transport, the set of procedures defined by the kinds of URLs that may be written,
and XML or JSON as the result type.</para>
<para>In contrast, rich client applications tend to have application code that is
tightly and rigidly coupled to the navigational structure of the underlying data.</para>
</sect2>
<sect2>
<title>Allowing cross-platform, open access to information</title>
<para>Whenever the Google spider indexes a web site, the web application on that
site is being used by a heterogeneous tool set.</para>
<para>Less grandly, web sites can be scraped and controlled by Microsoft Office
applications, by scripting languages, and by programming environments different
from the ones originally used to create them.</para>
<para>In each case, the end result is that making data URL-addressable enables
applications that the originators never conceived or imagined.</para>
</sect2>
<sect2>
<title>Deeplinking: a technology-neutral, URL-based integration platform</title>
<para>We have observed many benefits that URL addressing brings to web
applications</para>
<itemizedlist>
<listitem>
<para>Having multiple "start pages" and relaxing the navigation structure
within your application</para>
</listitem>
<listitem>
<para>Identifying bits of information, such as a video, slide show, or search
result using a form that is easy to store and share</para>
</listitem>
<listitem>
<para>Enabling applications to be broken into components. These components
may be defined by user interface pages (ie: a YouTube video) or may perform
an action and retrieve a result (ie: a RESTful AJAX invocation).</para>
</listitem>
<listitem>
<para>Allowing and encouraging open, cross-platform use of data, enabling
uses that the original application authors never imagined.</para>
</listitem>
</itemizedlist>
<para>We believe that it is time to make these benefits available to rich graphical
client applications as well. Deeplinking implements a solid first step toward enabling this
goal.</para>
</sect2>
</sect1>
<sect1>
<title>How does deeplinking work?</title>
<para>Deeplinking provides a specification and a Java/Eclipse RCP-based
reference implementation for how any rich graphical application can be made deeply
URL-addressable, and thus begin to participate and inter-operate in a networked,
hyperlinked world. Deeplinks work regardless of if the application is started; if it is
not already started, the deeplink URL handler will automatically launch it.</para>
<para>The best way to understand deeplinking is by describing how it works. Deeplink
URLs are of the following form:</para>
<programlisting>deeplink://appName/handlerType/handlerInstanceId/action?param1=value1&amp;param2=value2...</programlisting>
<para>where the action and parameters are optional. The appName is the name of the subdirectory
where the application lives. The remaining two segments are the handler type and the instance ID.
The handler type is the "type" of the "object" that the link addresses. The handlerInstanceId is
the string ID the application needs in order to look up an object of the specified type.</para>
<note>
<title>Unix directory structures</title>
<para>On Unix, it is recommended to place the applications files in an appropriate
application-specific directory and install a symbolic link to the application's
binary executable in the appropriate /bin folder, usually /usr/bin or /usr/local/bin.</para>
</note>
<para>For example, an Eclipse RCP application could have a following deeplink:</para>
<programlisting>deeplink://rcp-app/perspective/org.eclipse.rcp-app.client.perspective?customerid=some_customer_id</programlisting>
<para>The elements of this deeplink have the following meanings:</para>
<itemizedlist>
<listitem>
<para><computeroutput>rcp-app</computeroutput> : The name of the subdirectory that the application lives in</para>
</listitem>
<listitem>
<para><computeroutput>perspective</computeroutput> : This deeplink opens or displays a perspective</para>
</listitem>
<listitem>
<para><computeroutput>org.eclipse.rcp-app.client.perspective</computeroutput> : The Eclipse RCP perspective ID</para>
</listitem>
<listitem>
<para><computeroutput>?customerid=some_customer_id</computeroutput> : defines, in the same way as a web application, parameters
to pass to the Perspective Factory and thus into the application.
Specifically, the <computeroutput>IPerspectiveFactory </computeroutput> referenced by the perspective ID must extend the
<computeroutput>AbstractDeepLinkInstanceHandler</computeroutput> interface.
In our example, the perspective might then instruct
views or editors to load a particular trade or set the workbench selection to that trade.</para>
</listitem>
</itemizedlist>
<para>Deeplinking is designed so that any application that can listen to a network socket using the HTTP
protocol can participate. And the URL format is designed so that handler types can be created for
any kind of application: Eclipse RCP, Swing, .NET, etc. The one current restriction is that deeplinks
are a 100% local protocol. I.e: a deeplink:// URL always refers to an application running
on "localhost" and the deeplink URL handler resolves the port number assignment based on the
application name.</para>
</sect1>
<sect1 id="using-deep-linking">
<title>Using Deeplinking</title>
<para>The Eclipse deeplinking system has two parts:</para>
<itemizedlist>
<listitem>
<para>The deeplink launch proxy. This is a regular POJO command-line application that
Windows calls via the Windows Registry URL handler mechanism. This is needed to receive and translate
deeplinks into standard HTTP and forward to the RCP container.</para>
</listitem>
<listitem>
<para>A library that you can include in your RCP application that uses the built-in Eclipse
RCP servlet container to handle various types of RCP;-based deeplink URLs.
Additionally, applications that use this library can process HTTP responses received from
other deeplink aware applications.</para>
</listitem>
</itemizedlist>
<sect2>
<title>Building and configuring the deeplink launch proxy</title>
<para>You can use a pre-built launch proxy or you can build your own.</para>
<para>The launch proxy is 100% self-contained inside its own directory
structure, so installing and uninstalling it is simply a matter of copying it to the
location of your choice. You can then register it with Windows so that it will
automatically handle deeplink URLs that Windows encounters in desktop shortcuts or in
web pages.</para>
<para>To register your launch proxy with Windows, you will need to add some keys to
the Windows registry. A pre-built Windows registry configuration file is shipped
with the launch proxy. You can edit this configuration file and load its keys as
follows:</para>
<itemizedlist>
<listitem>
<para>Locate the <computeroutput>*.reg</computeroutput> file
that was shipped with launch proxy. You will find it in the root folder of
the launch proxy distribution.</para>
</listitem>
<listitem>
<para>Right-click this file, and choose <computeroutput>Edit</computeroutput>
from the context menu. You will need to use a text editor that knows how
to deal with multibyte character sets. On Windows, Notepad++ is a F/OSS
editor that works well.</para>
</listitem>
<listitem>
<para>Change the last line of the file to contain the full path and file name
of the <computeroutput>deeplink-launch.exe</computeroutput> file. You may
optionally specify an executable file containing an icon for deeplinks.</para>
</listitem>
<listitem>
<para>Save and exit the editor.</para>
</listitem>
<listitem>
<para>Double-click the .reg file to load it into Windows.</para>
</listitem>
</itemizedlist>
<para>You have now installed the deeplink launch proxy and have configured Windows to
understand the <computeroutput>deeplink://</computeroutput> URL type.</para>
</sect2>
</sect1>
<sect1>
<title>Using Deeplinking</title>
<para>For working examples, it is recommended to read the source code of the
examples shipped with deeplinking as these will always contain the latest
recommended usage patterns.</para>
<para>As described before, a generic deeplink URL is in the following form:</para>
<programlisting>deeplink://appName/handlerType/handlerInstanceId/action?param1=value1&amp;param2=value2...</programlisting>
<para>In order to use deeplinking, one may perform one of two tasks:</para>
<itemizedlist>
<listitem>
<para>Define deeplinks in one's application</para>
</listitem>
<listitem>
<para>Extend deeplinking to support additional handlerTypes</para>
</listitem>
</itemizedlist>
<para>This document will cover the former.</para>
<para>Out of the box, deeplinking supports two handlerTypes:</para>
<itemizedlist>
<listitem>
<para><computeroutput>perspective</computeroutput> : Open a perspective and optionally
execute a callback that may return data to the caller.</para>
</listitem>
<listitem>
<para><computeroutput>extensionpt</computeroutput> : Run a callback that is defined by
an Eclipse extension point. This callback also may optionally return data to the
caller.</para>
</listitem>
</itemizedlist>
<para>The good news is that out of the box, all Eclipse perspectives are automatically turned
into deeplinks of the form:</para>
<programlisting>deeplink://appName/perspective/com.your-company.your-app.perspective.id</programlisting>
<para>You do not need to do <emphasis>any</emphasis> work beyond enabling deeplinking to use these.</para>
<para>However, if you want your perspectives to process URL parameters or to return results,
or if you want to define a "headless" callback that can perform any arbitrary (UI or non-UI)
processing, you will need to do a small amount of additional work:</para>
<sect2>
<title>Defining a post-perspective-switch callback</title>
<para>In order to define a callback on a perspective, you only need to make your
perspective factory class extend the callback's abstract class and implement the callback
method.</para>
<programlisting>public class Perspective extends AbstractDeepLinkInstanceHandler implements IPerspectiveFactory {
public void createInitialLayout(IPageLayout layout) {
// your perspective initialization...
}
@Override
public Map&lt;String, String> activate(String handlerInstanceID,
String action, Map&lt;String, String[]> params) {
// Do whatever you want here. We'll return a simple Date value as an example...
HashMap&lt;String, String> result = new HashMap&lt;String, String>();
result.put("date", new Date().toString());
return result;
}
}</programlisting>
<para>That's it. You don't need to register your perspective callback
because it's <emphasis>already</emphasis> registered by its perspective ID. Deeplinking
will automatically look it up and call the callback if it exists.</para>
</sect2>
<sect2>
<title>Defining a "headless" extension point callback</title>
<para>An extension point callback is defined nearly the same way as a perspective
callback. The code looks like the following:</para>
<programlisting>public class SayHelloHandler extends AbstractDeepLinkInstanceHandler {
@Override
public Map&lt;String, String> activate(String handlerInstanceID, String action,
Map&lt;String, String[]> params) {
Map&lt;String, String> results = new HashMap&lt;String, String>();
String helloMessage = "Hello, " + action;
System.out.println(helloMessage);
results.put("Hello", helloMessage);
return results;
}
}</programlisting>
<para>Once you have the code, you have to register the callback using an extension
point:</para>
<itemizedlist>
<listitem>
<para>Go to the MANIFEST.MF editor for your bundle and switch to the "extensions"
tab.</para>
</listitem>
<listitem>
<para>Click "Add..." and add a new
<computeroutput>org.eclipse.e4.core.deeplink.typehandler.extensionpt.deepLinkExtensionPointInstanceHandler</computeroutput>
extension point.</para>
</listitem>
<listitem>
<para>Click on the child in the tree</para>
</listitem>
<listitem>
<para>Change the "id" field to the URL fragment that will identify the deeplink. For example,
our "Hello, world" extension point uses "sayhello" as its id.</para>
</listitem>
<listitem>
<para>Click "Browse..." and choose the class you created previously as your callback.</para>
</listitem>
</itemizedlist>
<para>Once this is done, your callback may be accessed using a URL of the form:</para>
<programlisting>deeplink://appName/extensionpt/id/optionalAction?param1=value1...</programlisting>
<para>Or to use the deep link defined by the code example above:</para>
<programlisting>deeplink://appName/extensionpt/sayhello/George</programlisting>
</sect2>
</sect1>
</chapter>