| <?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&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&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<String, String> activate(String handlerInstanceID, |
| String action, Map<String, String[]> params) { |
| // Do whatever you want here. We'll return a simple Date value as an example... |
| HashMap<String, String> result = new HashMap<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<String, String> activate(String handlerInstanceID, String action, |
| Map<String, String[]> params) { |
| Map<String, String> results = new HashMap<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> |