Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Orion/Documentation/Developer Guide/Architecture"

(Services)
(27 intermediate revisions by 5 users not shown)
Line 1: Line 1:
= Overview =  
+
= Architecture overview =  
  
 
Orion consists of loosely coupled components written in JavaScript, and server-side services exposed via REST-oriented HTTP APIs. These components and services can be combined in many different ways to create various kinds of applications. The natural expression of the Orion vision is Browser-based tools written in JavaScript interacting with data in the cloud via REST APIs. However parts of Orion can also be used in traditional desktop clients as well as server side applications. The data being manipulated by such tools can reside either on a remote server or a local machine. The architecture of your Orion-based application will often be driven by other constraints. Operating on local data offers better performance and facilitates offline usage, but doesn't provide the always secure, always backed up nature of storing data on the server. Whether your tools run in a browser or a rich client may depend on what other development tools you need to work with.  
 
Orion consists of loosely coupled components written in JavaScript, and server-side services exposed via REST-oriented HTTP APIs. These components and services can be combined in many different ways to create various kinds of applications. The natural expression of the Orion vision is Browser-based tools written in JavaScript interacting with data in the cloud via REST APIs. However parts of Orion can also be used in traditional desktop clients as well as server side applications. The data being manipulated by such tools can reside either on a remote server or a local machine. The architecture of your Orion-based application will often be driven by other constraints. Operating on local data offers better performance and facilitates offline usage, but doesn't provide the always secure, always backed up nature of storing data on the server. Whether your tools run in a browser or a rich client may depend on what other development tools you need to work with.  
Line 10: Line 10:
 
# '''Remote client / remote data'''. Server side tools written in Java, accessing local Orion services (for example a build server working against an Orion workspace server on the same machine).
 
# '''Remote client / remote data'''. Server side tools written in Java, accessing local Orion services (for example a build server working against an Orion workspace server on the same machine).
  
[[Image:Orion_Architecture_1.jpg|center|400px|border]]
+
[[Image:Orion_Architecture_1.jpg|Orion Architecture Overview|center|400px|border]]
  
 
= Client architecture =
 
= Client architecture =
Line 18: Line 18:
 
Orion aims to provide independently useful web components with minimal coupling between them, so that application developers can choose to deploy only the subsets of interest to their applications. Each component is represented by a JavaScript library (typically a single JavaScript file) and any directly associated resources like style sheets or images. With Orion we consciously do not mandate the use of a special packaging format or component library requirement so you can for example use your favorite DOM manipulation library as is.  
 
Orion aims to provide independently useful web components with minimal coupling between them, so that application developers can choose to deploy only the subsets of interest to their applications. Each component is represented by a JavaScript library (typically a single JavaScript file) and any directly associated resources like style sheets or images. With Orion we consciously do not mandate the use of a special packaging format or component library requirement so you can for example use your favorite DOM manipulation library as is.  
  
For the moment “implementation-level” dependencies between components in Orion are managed using a limited and relatively manual form of dependency injection. At some point in the near-term future (and given recent events) we’re expecting to move our component model over to using some variant of CommonJS/AMD though as alluded to above web components are not forced into using this model. For more loosely coupled functional interactions Orion provides both a service registry and an extension registry (both described below) not unlike what we currently have in desktop Eclipse.
+
Dependencies between components in Orion are managed using the [http://www.commonjs.org/ CommonJS] [http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition AMD] module format. However, as alluded to above, web components are not forced into using this model. For more loosely coupled functional interactions Orion provides a service registry similar to the OSGi service model, but with some of the declarative characteristics of Eclipse extension and extension points.
  
 
== Services ==
 
== Services ==
Line 26: Line 26:
 
Here is a simplified example of the <tt>Explorer</tt> object using a service to prompt the user to confirm a file deletion:
 
Here is a simplified example of the <tt>Explorer</tt> object using a service to prompt the user to confirm a file deletion:
  
   function Explorer(serviceRegistry, treeRoot, breadcrumbParentId, searcher, parentId, navToolBarId) {
+
   function Explorer(serviceRegistry, ...) {
       '''this.registry = serviceRegistry;'''
+
       this.registry = serviceRegistry;
 
       ...
 
       ...
 
   }
 
   }
Line 33: Line 33:
 
   deleteFile: function(itemId) {
 
   deleteFile: function(itemId) {
 
       var item = this.myTree.getItem(itemId);
 
       var item = this.myTree.getItem(itemId);
       this.'''registry.callService'''("IDialogService", "confirm", null,
+
       var service = <b>registry.getService</b>("orion.page.dialog");
        ["Are you sure you want to delete '" + item.Name + "'?",
+
      var message = "Are you sure you want to delete '" + item.Name + "'?";
       ...
+
       service.confirm(message, function(doit) { /* perform deletion */});
 
   }
 
   }
  
The format of the <tt>callService</tt> function is fairly straight-forward. The caller specifies the name of the library, the function to call, and the function arguments as an array. The additional parameter ('null' in the example above), allows a client to provide a callback function that receives the return value of the service invocation. One particularly important point to emphasize is that '''all''' service calls through the service registry are '''asynchronous'''. You cannot assume that the service function will have been executed by the time the <tt>callService</tt> method returns. This attribute allows the service implementation to employ a variety of long-running techniques to execute the service, such as calls to a remote web service, cross-domain postMessage, HTML5 web workers, etc.
+
The <tt>getService</tt> function takes the service name as argument, and returns either the service instance or null. For this example we're assuming the service is present. However &mdash; especially when using services dynamically contributed from a plugin &mdash; you should check for <code>null</code>. One particularly important point to emphasize is that ''all'' service calls through the service registry are ''asynchronous'' and return a [http://wiki.commonjs.org/wiki/Promises/A promise] object (such as a Dojo [http://dojotoolkit.org/api/1.6/dojo/Deferred Deferred]). You cannot assume that the service function will have been executed by the time the service function returns and instead must chain any follow-on calls to the "promise". This allows the service implementation to employ a variety of long-running techniques to execute the service, such as calls to a remote web service, cross-domain postMessage, HTML5 web workers, etc.
  
The service object can also be obtained directly for clients that need to make more complex interactions with the service (such as invoking multiple functions against the service in sequence).
+
=== Service definitions ===
 +
 
 +
A service definition includes both a declarative aspect, and optionally a concrete service object. Declarative service properties can be cached by the Orion service registry, avoiding loading of the plug-in providing that service until it is needed. The following is an example of a very simple service definition:
 +
 
 +
  var provider = new orion.PluginProvider();
 +
  var serviceImpl = {
 +
    run : function(text) {
 +
      return text.toUpperCase();
 +
    }
 +
  };
 +
  var serviceProps = {
 +
    name : "UPPERCASE",
 +
    img : "/images/gear.gif",
 +
    key : [ "u", true ]
 +
  };
 +
  provider.registerService("orion.edit.command", serviceImpl, serviceProps);
 +
  provider.connect();
 +
 
 +
This service registers a new command in the editor. The service implementation has a single <tt>run</tt> method that converts the provided text to upper case. The service properties specify the name of the command, the icon, and key binding. This way the editor can display the command in the toolbar using the cached service properties, without actually loading the plugin.
  
 
== Extensions ==
 
== Extensions ==
  
As a means of declarative contribution Orion will continue to promote the use of extensions and extension points. Extensions as used by Orion are conceptually very similar to what we currently use in the desktop and in particular will continue to have broad support in the UI and provide excellent lazy activation characteristics. One notable difference with the desktop is that code level functionality is always provided by a service reference instead of through class instantiation. Another difference is that Orion uses JSON instead of XML as a representation format for extensions.
+
Orion implements the Eclipse concept of extensions and extension points using the Orion service registry. An extension point is simply a service interface that clients are expected to implement. Each instance of that service is an extension. You will often see the terms "extension" and "service" used interchangeably in the Orion documentation. There is no technical difference between them; rather, it is an expression of how the service is intended to be used. Services provided by clients are conceptually extensions, and services used by clients are simply called services.
  
 
== Plugins ==
 
== Plugins ==
  
Services and Extensions outside of the base platform are contributed to Orion by registering plugins. A plugin is declared via an HTML file, is opened in a "head-less" child IFrame and uses window.postMessage to advertise capabilities in the form of services and extensions back to Orion. Orion persists plugin information and at a later date when functionality is requested the plugin will be re-loaded either in an IFrame, in a Web Worker, or in-line as a web component based on security restrictions and functionality offered.  
+
Services and extensions that reside on different web domains from the host Orion server are contributed to Orion by registering plugins. A plugin is declared via an HTML file, is opened in a "head-less" child <tt>IFrame</tt> and uses <tt>window.postMessage</tt> to advertise capabilities in the form of services and extensions back to Orion. Orion persists plugin information and at a later date when functionality is requested the plugin will be re-loaded either in an <tt>IFrame</tt>, in a Web Worker, or in-line as a web component based on security restrictions and functionality offered. Here is an example of a simple plug-in:
  
 
   <!DOCTYPE html>
 
   <!DOCTYPE html>
 
   <html>
 
   <html>
 
   <head>
 
   <head>
 +
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 
     &lt;!-- Dependencies --&gt;
 
     &lt;!-- Dependencies --&gt;
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
     <script type="text/javascript" src="../orion/plugin.js"></script>
     <script type="text/javascript" src="/openajax/release/all/OpenAjaxManagedHub-all.js"></script>
+
     <script>
     <script type="text/javascript" src="js/plugin.js"></script>
+
      window.onload = function() {
    &lt;!-- Contributed Scripts --&gt;
+
        &lt;!-- Service declarations go here --&gt;
    <script type="text/javascript" src="js/jslintworker.js"></script>
+
      };
     <script type="text/javascript" src="js/jslintPlugin.js"></script>
+
     </script>
 
   </head>
 
   </head>
 
   <body>
 
   <body>
Line 65: Line 84:
 
   </html>
 
   </html>
  
The corresponding JavaScript then contributes its services by using the <tt>ServiceProvider.extend</tt> function:
+
A simple plugin can consist of only the plugin's HTML file, and the required <tt>plugin.js</tt> script from Orion. More complex plugins will typically include several script files containing the concrete service implementation objects.
  
  eclipse.JSLintServiceProvider.prototype = eclipse.ServiceProvider.extend({
+
Plugins are installed or uninstalled from the <b>Settings</b> page within the Orion user interface.
    checkSyntax: function(title, contents) {
+
      ...
+
    }
+
  });
+
 
+
Currently, plugins must be declared and started manually, but in the future we expect to simplify this. Here is a current example of starting a plugin programmatically. This example contributes one service library called <tt>IEditorSyntaxChecker</tt>, with a single method <tt>checkSyntax</tt>.
+
 
+
  var pluginData = {
+
    services : [{
+
      id : "JSLintEditorSyntaxChecker",
+
      serviceType : {
+
        id: "IEditorSyntaxChecker",
+
        interfaces : ["checkSyntax"]
+
      },
+
      properties: {}
+
    }]
+
  };
+
  var serviceProvider = new eclipse.JSLintServiceProvider();
+
  new eclipse.Plugin(pluginData, serviceProvider).start();
+
  
 
= Server architecture =
 
= Server architecture =
 
== Server APIs ==
 
== Server APIs ==
  
Orion defines a number of server APIs accessed via simple REST-oriented HTTP calls. These server APIs do not presuppose any particular server technology over straight HTTP, and JSON as the default representation format. Application developers are free to implement Orion server API with the server language and infrastructure of their choice. For a detailed listing of server APIs, see [[EclipseWeb/Server API]].
+
Orion defines a number of server APIs accessed via simple REST-oriented HTTP calls. These server APIs do not presuppose any particular server technology over straight HTTP, and JSON as the default representation format. Application developers are free to implement Orion server API with the server language and infrastructure of their choice. For a detailed listing of server APIs, see [[Orion/Server API]].
  
== Example Server ==
+
== Example server ==
  
 
The current Orion server is written in Java, using [[Jetty]] and [[Equinox]] server infrastructure. This server does not currently define any Java API for extending or augmenting its behavior. Applications should be written against the HTTP server API, to allow for portability across server implementations. To avoid the perception of Orion providing a monolithic, definitive, extensible, irreplaceable server, the server is often referred to as an "example server".
 
The current Orion server is written in Java, using [[Jetty]] and [[Equinox]] server infrastructure. This server does not currently define any Java API for extending or augmenting its behavior. Applications should be written against the HTTP server API, to allow for portability across server implementations. To avoid the perception of Orion providing a monolithic, definitive, extensible, irreplaceable server, the server is often referred to as an "example server".
Line 111: Line 111:
  
 
The server is split up this way to allow the pieces to be used in other server containers. You can discard the configurator bundle, and create your own server using the provided servlets and common code. This allows you to completely control the server layout, authentication, etc, for your server.
 
The server is split up this way to allow the pieces to be used in other server containers. You can discard the configurator bundle, and create your own server using the provided servlets and common code. This allows you to completely control the server layout, authentication, etc, for your server.
 
 
[[Category:Orion|Architecture]]
 

Revision as of 12:13, 8 February 2013

Architecture overview

Orion consists of loosely coupled components written in JavaScript, and server-side services exposed via REST-oriented HTTP APIs. These components and services can be combined in many different ways to create various kinds of applications. The natural expression of the Orion vision is Browser-based tools written in JavaScript interacting with data in the cloud via REST APIs. However parts of Orion can also be used in traditional desktop clients as well as server side applications. The data being manipulated by such tools can reside either on a remote server or a local machine. The architecture of your Orion-based application will often be driven by other constraints. Operating on local data offers better performance and facilitates offline usage, but doesn't provide the always secure, always backed up nature of storing data on the server. Whether your tools run in a browser or a rich client may depend on what other development tools you need to work with.

The following are examples of architectural configurations that Orion components and services can be used in:

  1. Browser client / remote data. This is a pure web model. A browser-based client using Orion JavaScript client libraries and accessing remote Orion services via REST API.
  2. Mixed client / local data. A rich client (traditional Eclipse client), which contains a mixture of "legacy" components written in Java and web components written in JavaScript. The JavaScript components interact with JavaScript libraries and/or REST APIs, while Java components interact with the Eclipse Platform Java APIs.
  3. Rich client / remote data. Traditional Eclipse client components interacting with remote Orion services via REST API. This enables a mixture of rich client and browser-based tools to inter-operate against the same server-side data.
  4. Remote client / remote data. Server side tools written in Java, accessing local Orion services (for example a build server working against an Orion workspace server on the same machine).
Orion Architecture Overview

Client architecture

Web components

Orion aims to provide independently useful web components with minimal coupling between them, so that application developers can choose to deploy only the subsets of interest to their applications. Each component is represented by a JavaScript library (typically a single JavaScript file) and any directly associated resources like style sheets or images. With Orion we consciously do not mandate the use of a special packaging format or component library requirement so you can for example use your favorite DOM manipulation library as is.

Dependencies between components in Orion are managed using the CommonJS AMD module format. However, as alluded to above, web components are not forced into using this model. For more loosely coupled functional interactions Orion provides a service registry similar to the OSGi service model, but with some of the declarative characteristics of Eclipse extension and extension points.

Services

References between client library objects are directed through a service registry. Library objects are provided with a service registry object on construction, allowing a developer using the library to override what service implementations are used by any given library object. For example, while the default implementation of the Preferences object uses the remote preference service over HTTP, a client could provide an implementation that uses HTML5 local storage, cookies, etc.

Here is a simplified example of the Explorer object using a service to prompt the user to confirm a file deletion:

 function Explorer(serviceRegistry, ...) {
     this.registry = serviceRegistry;
     ...
  }
  ...
  deleteFile: function(itemId) {
     var item = this.myTree.getItem(itemId);
     var service = registry.getService("orion.page.dialog");
     var message = "Are you sure you want to delete '" + item.Name + "'?";
     service.confirm(message, function(doit) { /* perform deletion */});
  }

The getService function takes the service name as argument, and returns either the service instance or null. For this example we're assuming the service is present. However — especially when using services dynamically contributed from a plugin — you should check for null. One particularly important point to emphasize is that all service calls through the service registry are asynchronous and return a promise object (such as a Dojo Deferred). You cannot assume that the service function will have been executed by the time the service function returns and instead must chain any follow-on calls to the "promise". This allows the service implementation to employ a variety of long-running techniques to execute the service, such as calls to a remote web service, cross-domain postMessage, HTML5 web workers, etc.

Service definitions

A service definition includes both a declarative aspect, and optionally a concrete service object. Declarative service properties can be cached by the Orion service registry, avoiding loading of the plug-in providing that service until it is needed. The following is an example of a very simple service definition:

 var provider = new orion.PluginProvider();
 var serviceImpl = {
   run : function(text) {
     return text.toUpperCase();
   }
 };
 var serviceProps = {
   name : "UPPERCASE",
   img : "/images/gear.gif",
   key : [ "u", true ]
 };
 provider.registerService("orion.edit.command", serviceImpl, serviceProps);
 provider.connect();

This service registers a new command in the editor. The service implementation has a single run method that converts the provided text to upper case. The service properties specify the name of the command, the icon, and key binding. This way the editor can display the command in the toolbar using the cached service properties, without actually loading the plugin.

Extensions

Orion implements the Eclipse concept of extensions and extension points using the Orion service registry. An extension point is simply a service interface that clients are expected to implement. Each instance of that service is an extension. You will often see the terms "extension" and "service" used interchangeably in the Orion documentation. There is no technical difference between them; rather, it is an expression of how the service is intended to be used. Services provided by clients are conceptually extensions, and services used by clients are simply called services.

Plugins

Services and extensions that reside on different web domains from the host Orion server are contributed to Orion by registering plugins. A plugin is declared via an HTML file, is opened in a "head-less" child IFrame and uses window.postMessage to advertise capabilities in the form of services and extensions back to Orion. Orion persists plugin information and at a later date when functionality is requested the plugin will be re-loaded either in an IFrame, in a Web Worker, or in-line as a web component based on security restrictions and functionality offered. Here is an example of a simple plug-in:

 <!DOCTYPE html>
 <html>
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   <!-- Dependencies -->
   <script type="text/javascript" src="../orion/plugin.js"></script>
   <script>
     window.onload = function() {
       <!-- Service declarations go here -->
     };
   </script>
 </head>
 <body>
 </body>
 </html>

A simple plugin can consist of only the plugin's HTML file, and the required plugin.js script from Orion. More complex plugins will typically include several script files containing the concrete service implementation objects.

Plugins are installed or uninstalled from the Settings page within the Orion user interface.

Server architecture

Server APIs

Orion defines a number of server APIs accessed via simple REST-oriented HTTP calls. These server APIs do not presuppose any particular server technology over straight HTTP, and JSON as the default representation format. Application developers are free to implement Orion server API with the server language and infrastructure of their choice. For a detailed listing of server APIs, see Orion/Server API.

Example server

The current Orion server is written in Java, using Jetty and Equinox server infrastructure. This server does not currently define any Java API for extending or augmenting its behavior. Applications should be written against the HTTP server API, to allow for portability across server implementations. To avoid the perception of Orion providing a monolithic, definitive, extensible, irreplaceable server, the server is often referred to as an "example server".

The current server is structured into the following bundles(bundle names subject to change):

org.eclipse.orion.server
Provides common provisional server API used by other parts of the server
org.eclipse.orion.server.servlets
Defines servlets for the core Orion services: file, workspace, preferences
org.eclipse.orion.server.search
Search servlet implementation using Apache Solr/Lucene
org.eclipse.orion.server.configurator
Defines an application, and configures the server (registers servlets and static content, specifies authentication and authorization settings)
org.eclipse.orion.server.authentication.*
Bundles providing various kinds of authentication support.

The server is split up this way to allow the pieces to be used in other server containers. You can discard the configurator bundle, and create your own server using the provided servlets and common code. This allows you to completely control the server layout, authentication, etc, for your server.

Copyright © Eclipse Foundation, Inc. All Rights Reserved.