BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles An Overview of the eXo Platform

An Overview of the eXo Platform

This item in japanese

Bookmarks

EXo Platform is pleased to announce the release of its new Portlet Container 2.0 and Portal 2.1. eXo is the first portal offering to provide full support - consumer and provider - of the new Java Portlet 2.0 API (JSR 286) and Web Service Remote Portlet 2.0 (WSRP). This announcement  is the opportunity to take a look to the new features provided by eXo Portal, Portlet-Container and Enterprise Content Management (ECM).

Overview of the eXo Platform Architecture

Before going into the details of the Portal, Portlet Container and ECM components of the eXo Platform offering, it is important to give an overview of the platform architecture.

Since the very first version of eXo Platform, an Inversion Of Control (IoC) container named Pico Container was used to provide loose coupling of dependencies between services. It is the container’s responsibility to instantiate component implementations and to inject them into the dependent component.

All the components of the eXo Platform are developed as plugins and wired together using the IoC container. The next diagram shows each of the components in the eXo platform stack from the lower levels to the higher ones:

 

The Web 2.0 Portal

The new version of eXo Portal is built on what was introduced in the previous version, and we eliminated the user complexity which the extensible model added thanks to Web 2.0 technologies such as AJAX.

Indeed, eXo was the first to introduce the concept of dynamic layouts at a time when most other portals were using static layouts. The main difference is that, with dynamic layouts, you are managing a tree of nested containers, the leaves of which are the portlets. The containers are responsible for the layout of their children, just like when manipulating Swing UI objects, as shown in the next diagram. The container renderers which are available out of the box will display children either in rows, columns or tabs.

As a result, moving a container from one location to another is just a tree manipulation on the data structure side. On the client side we have used JavaScript code to create Drag-and-Drop libraries which ease that tree manipulation. Therefore, as shown in the next screenshot, it is possible to not only drag and drop containers and portlets inside the page, but also to drag into the page a type of container or portlet.

Each portlet has a set of metadata that allows the portal to render it in the page. This metadata includes the title, size, icon and border look (as in the next screenshot) but also whether we should display the border and it’s icons at all (to minimize or maximize the portlet).

Once  all this information is filled , it is possible for the Portal to render pages which are in fact of different types. Each type is aggregated into the user’s menu when the user logs in (as shown on the next screenshot). The pages types are:

  • Portal pages which are the pages every user will see. Some of those pages are even viewable by anonymous users which can be the basis for an extranet or internet site such as our own
  • User pages that can be seen as a set of dashboards where the user can add new pages and their content (only if the company policy allows it though)

     

  • Group pages that will add to the user menu the pages of the group they are in, such as the marketing or sales ones

You can also see in the previous screenshot a left collapsible column that appears when the user logs in. It contains a way to navigate among the pages and some administration menus as well as a set of widgets that users can configure as they want. As we said, widgets are full JavaScript components that communicate with the server using the REST protocol. In a future version, these will be based on the Google OpenSocial standard.

eXo Portal 2.0 is also a full AJAX portal, which means that when you move from one page to another only a part of the screen is refreshed. To do so, we use the JavaScript XMLHttpRequest object to call the server asynchronously each time a page is changed or the content of one or several portlets in the page have to be modified (as in the case when one portlet sends a message to another one using JSR 286 standard calls). This of course greatly improves the server calls since, unless events are sent, only one render() is necessary. This is contrast to the normal use case in which every portlet has to render its fragment, which takes much more time (even if it is cached).

At each request, the portal returns an XML file that wraps all of the different HTML fragments which are to be updated in the page. The structure of that XML file is:

 * {PortalResponse}
  *      |
  *      |--->{PortletResponse}
  *      |
  *      |--->{PortletResponse}
  *      |          |-->{portletId}
  *      |          |-->{portletTitle}
  *      |          |-->{portletMode}
  *      |          |-->{portletState}
  *      |          |
  *      |          |-->{PortletResponseData}
  *      |                 |
  *      |                 |--->{BlockToUpdate}
  *      |                 |         |-->{BlockToUpdateId}
  *      |                 |         |-->{BlockToUpdateData}
  *      |                 |
  *      |                 |--->{BlockToUpdate}
  *      |
  *      |--->{PortalResponseData}
  *      |      |
  *      |      |--->{BlockToUpdate}
  *      |      |         |-->{BlockToUpdateId}
  *      |      |         |-->{BlockToUpdateData}
  *      |      |
  *      |      |--->{BlockToUpdate}
  *      |
  *      |--->{PortalResponseScript}

The server response contains 3 types of XML:

  • one for the portal components fragment, included in the <PortalResponseData> tag -- this also wraps the ID of the component to update
  •  
  • one for each portlet fragment to update -- this also wraps portlet information such as the window state and portlet modes to update. Portlets that are aware of eXo Portal 2.x AJAX feature can also tell the portal which HTML tags to directly update to avoid a full portlet refresh (which is mandatory for fully compliant JSR 286 portlets)
  • The JavaScript code which does dynamic evaluation, so that it is available in the new generated page

The returned JavaScript inside the <PortalResponseScript> is generated by the portal or the portlets which understand eXo portal’s handling of JavaScript. Furthermore, the returned JavaScript needs to define global JavaScript functions (using the syntax function() ) to be dynamically added to the page during the eval() method. Here again, if the portlet is a pure JSR 286 one, it will not be able to use that convenient way. In that case, the portal parses the <PortletResponseData> and sees that no blockToUpdate has been set up. Hence, it will parse the entire portlet fragment to find all the scripts so that they can be added to the page. Several third-party JSR 168 portlets that include JavaScript have been tested such as the SpagoBI ones.

One other great improvement in the new eXo Portal is that all portal configuration files (including the group, user and portal pages as well as the widgets or portlet preferences) are now stored in the standard repository. We see in the next screenshot that the root user pages are stored in an XML file at the JCR location /exo:registry/exo:users/root/UserPortalData:

Using a JCR layer is not only convenient for its storage performance and clustering capabilities but also for the advanced services which JCR provides, such as a native exposure through a REST service (to allow third parties applications to manipulate portal pages).

eXo Portlet Container: JSR 286 and WSRP 2

eXo Portlet Container 2.0 implements two new major specifications of the Java and Web services portal world:

  • Portlet API 2.0
  •  
  • WSRP 2

As part of the portal, the portlet container is responsible for managing the applications that will be exposed in the multi-window environment.

For this new version, we have dramatically revamped the inner architecture. We have notably leveraged the previously introduced plugin mechanism, hence providing an extension point to the portlet container.

Portlet API 2.0 (JSR 286)

The Portlet API 2.0 was released  on June 13th 2008, and eXo is the first implementation to be compliant and provide both the portlet container and the portal to consume these portlets. The specification is an extension of the JSR 168, and the expert group has put a special focus on ensuring that the JSR 168 portlets will work in a JSR 286 container.

The Portlet 2.0 API introduces many new features such as:

  • Inter-Portlet Communication (IPC) which allows the sending of events and parameters to other portlets (not necessary in the same WAR)
  • Portlet Filters to mimic the servlet filters behavior
  • Public Parameters to share render parameters with all portlets during the render phase
  • Advanced Cache Behavior as this part was very limited in JSR 168
  • A new serverResource() method to better handle image insertion (instead of going through a servlet)
  • An URL Listener mechanism to trigger a handler when an URL is called

Inter-Portlet Communication explained

We will not go through all the new features in the JSR 286 specification but we will describe in detail a major one: Inter-Portlet Communication (aka IPC).

Before going in the details of the IPC process, let’s take a look at what the process is in the context of the JSR 168 portlet request.  In JSR 168, a request was split in two phases:

  1. processAction() : which targets a single portlet to change the state of a business object like a JavaBean
  2. render() : which is called on every portlet of the page and which is responsible for rendering the HTML fragment

It is important to see that a 2 phase request was mandatory as the rendered HTML fragments could be dependent on a modified JavaBean object and hence the processAction() method should occur before any render() call.

From this, we can see that JSR 168 only defines user interface rendering in the context of a single portlet. It does not define any standard way regarding the communication between portlets that is a key point to build composite applications.

That said, developers have often taken advantage of the fact that you can share a JavaBean object between multiple portlets using the HTTP session. However, this is restrictive since this sort of session-based sharing is limited to the portlets that are deployed in the same WAR.

In a real life scenario, portlets may come from different providers and be bundled in different WARs. Still we would like to provide some interaction between portlets, allowing the portal user to create powerful composite applications. For example, you may have built an address book portlet that displays the details of a user including their address, and want to update a third-party portlet that uses Google Maps web services to show the address location on a map.

That is why the JSR 286, as shown in the next sequence diagram (taken from the specification text itself), has introduced a processEvent() phase, which will trigger events at the end of the processAction() phase:

An event is launched from the processAction() action method by attaching it to the ActionResponse object (which extends PortletResponse). The portlet container then propagates the event to the portal layer that is responsible for identifying which portlet instances the event should target.

Event dispatching is outside of the specification scope, but one solution at the portal level is to target every portlet instance located in the same page and that can handle the event. Note that a processEvent() method can also trigger a new event. It is the responsibility of the portal to avoid infinite cyclic calls.

IPC configuration

The IPC configuration of a portlet is done in the portlet.xml file.

<portlet>
     <description xml:lang="EN">TestProcessEvent</description>
     <portlet-name>TestProcessEvent</portlet-name>
     <display-name xml:lang="EN">Test ProcessEvent</display-name>
     <portlet-class>
       org.exoplatform.services.portletcontainer.test.portlet2.TestProcessEvent
     </portlet-class>
     <expiration-cache>0</expiration-cache>
     <cache-scope>PRIVATE</cache-scope>
     <supports>
       <mime-type>text/html</mime-type>
       <portlet-mode>view</portlet-mode>
       <portlet-mode>edit</portlet-mode>
       <portlet-mode>help</portlet-mode>
     </supports>
     <supported-locale>EN</supported-locale>
     <portlet-info>
       <title>TestProcessEvent</title>
       <short-title>TestProcessEvent</short-title>
     </portlet-info>
     <supported-processing-event><name>MyEventPub</name></supported-processing-event>
     <supported-publishing-event><name>MyEventPub</name></supported-publishing-event>
   </portlet>

   [...]

   <event-definition>
     <name>MyEventPub</name>
     <value-type>
       org.exoplatform.services.portletcontainer.test.portlet2.MyEventPub
     </value-type>
   </event-definition> 

In this example, the same portlet publishes and processes the event. Indeed, in a real life example that would be two different portlets! Note that an event alias is used and that the associated event class is defined only once within the XML file.

Using IPC

A portlet usually extends the GenericPortlet class, which itself implements the EventPortlet interface that defines the processEvent() method.

Below is a code sample that shows how to register the event object in the processAction() method and how to retrieve it in the processEvent() method:

  public void processAction(ActionRequest actionRequest, ActionResponse actionResponse)
       throws PortletException, IOException {
     MyEventPub sampleAddress = new MyEventPub();
     sampleAddress.setStreet("myStreet");
     sampleAddress.setCity("myCity");
     actionResponse.setEvent(new QName("MyEventPub"), sampleAddress);
   }

   public void processEvent(EventRequest req, EventResponse resp)
       throws PortletException, IOException {
     System.out.println("In processEvent method of EventDemo... !!!!!!!!!!!!!");
     Event event = req.getEvent();
     System.out.println("  -- name: " + event.getName());
     System.out.println("  -- value: " + event.getValue());
     MyEventPub sampleAddress = new MyEventPub();
     sampleAddress = (MyEventPub) event.getValue();
     resp.setPortletMode(PortletMode.EDIT);
   }

Please note that the WSRP 2 specification also supports the processEvent() phase, and hence events can be propagated from the consumer to the producer on another server, developers just have to make sure that the event can be serialized using JAXB.

Standalone Portlet Container

eXo Portlet Container 2.0 can be downloaded as a standalone application to ease its embedding within third-party applications. It comes with a light administration portal that showcases compatibility of your JSR 286 portlets as shown in the next screenshot. You can select one or several portlets that were deployed in a WAR and see them.

In the following screenshot, we have selected the ResourceDemo portlet which displays a picture using the serverResource() method as well as some markup returned after making an AJAX call:

Embedded Portlet Container

As they are standard portlets, you can also deploy the portlets2.war in the eXo enterprise Portal or WebOS to test and learn about the new specification.

You will need to open the Application Registry. This administration portlet lets you browse portlets organized by category. There is a button to quickly import all the deployed portlet application WARs:

The screenshot shows the "portlets2" category that you should obtain after deploying and importing the portlets2.war. On the right, you will see our demo JSR 286 portlets like TestPublicParam2 and TestProcessEvent1.

Once properly configured (permissions can be applied), you can add the portlets to a desktop page using the "+" icon to the left of the dock bar:

Here, many portlets were added to the dock and we display 3 of them: TestPublicParam1, TestPublicParam2 and TestPublicParam3. These portlets demo the new JSR 286 Public Parameters.

This feature allows you to set some render parameters in the processAction() phase. These parameters are then accessible in all the render() methods of all the portlets. In JSR 168, render parameters were only viewable by the associated portlet.

In the previous screen, if we click on the "set public param" option of portlet 1 or 2 we see that the public parameters are available in the 3 portlets. If we click that link in the third portlet, the public parameters of portlet 1 and 2 will be overridden by the one from the third portlet.

WSRP 2

In addition to the Java Portlet API, Web Services Remote Portlet 2.0 (WSRP) has been also updated to support the new features we have discussed above.

It is now possible to provide a plugin implementation that will expose external components to the portal layer as if they were true portlets. A real life example of such a plugin, as shown in the next picture, is the WSRP 2 consumer plugin which will expose remote portlets to the portal in the exact same way as local portlets are exposed by the JSR 286 plug-in.

The advantage of this is that the portal UI will similarly handle local and remote portlets: there is no need for JSR 168 or 286 proxy portlets anymore. These were intrusive as the user had to configure things such as the remote address of the WSDL file in the portlet preferences. This task is now the responsibility of the administrator when configuring the consumer plug-in.

The WSRP producer architecture did not change much, but the code itself was completely rewritten. During 2008, we will continue to check the consumer / producer interoperability with other market players as soon as there are other producer and consumers available to test against.

The WebOS: a portal layout

Technically speaking, the WebOS is simply a custom layout for the Portal 2.0 release. It means that the portlets do not need to be within a container. Hence, portlets and widgets are displayed as draggable windows that can overlap each other, just like a standard operating system on your desktop, but all within the confines of your browser. Since a page is displayed as a multi-window environment, it is possible to have several desktops (portal, group or users ones) exactly as with the normal portal. For instance, one desktop could contain collaboration applications such as Mail, Calendar or Content (like in the next screenshot) while another desktop would contain the portlet that access the ERP backend.

The goal of the WebOS is to reproduce inside of a browser the best ergonomics patterns. That is why we have mixed features and skins from several existing operating systems inside a unique environment. The most notable ones are:

  • The dock which contains portlets of the WebOS page. A right click on one icon lets you remove the portlet from the dock.  The next two screenshots show the dock but displayed in two different skins. The "+" button allows you to add new portlets to the dock and the page which the user has the right to use.
  • The "start menu" on the left column allows users to access publishing and administration features such as wizards to create new pages. It also provides a way to change the locale in use or to alter the selected skin. As previously noted, it also allows users to define a set of widgets that will be available for all pages whereas the widgets added inside the WebOS page only live there.

Any of the Portlets and Widgets that are available in the eXo Application Registry can be used in the WebOS layout.

eXo Java Content Repository and ECM

In addition to its new portal, eXo Platform just released a new version of its Enterprise Content Management (ECM) solution that uses JCR as foundation, just as in the portal.

Java Content Repository: the file system

eXo Java Content Repository (eXo JCR) is our implementation of JSR 170. It normalizes how content is structured, versioned, locked and searched while being stored in a centralized repository. Similar to other components of the eXo Platform, this product comes with a lot of optimizations and extensions as shown in the next schema. These are all available in the standalone distribution of the product which can be downloaded on the OW2 forge.

The JCR’s schema can be split into 3 areas:

  • The core part which is the specification implementation and some API extensions as well as how eXo manages the storage part
  • The protocols connectors such as FTP, CIFS, WebDAV, DeltaV, DASL
  • The applications and plugins built such as Microsoft Office and Open Office plugins

These three parts with be explored in more detail.

JCR Core

The eXo JCR implementation is a multi-repository and multi-workspace implementation of JSR 170. The entry point of a JCR backend is a repository object, but it is not mandatory in the specification to provide several repositories; nevertheless this is quite useful in some situations.

A repository gives access to one or several workspaces; here again the specification does not enforce support for several workspaces, however we have chosen to implement it since it is a useful capability.

Once in a workspace, you can browse a tree of Nodes that can be seen as an enhanced version of a standard file system’s folders. The leaves of the tree are Property objects which can be of several types, such as Date or Binary. If we use the File System analogy, you can see the binary properties as the file. All this is described in the next diagram:

In the eXo implementation, each workspace can point to a different database where all the metadata information such as the path of the file as well as some properties (like Dublin Core metadata) are stored. For performance reasons, the files themselves can be stored on an associated file system (NAS, SAN...). Each workspace can also configure some advanced caching, buffering, swapping, indexing or security policies. Clustering of the repositories is also possible when scalability is required.

The next XML fragment shows the custom configuration file used to setup a JCR environment. We can define all of the repository configuration there, but we will only describe one workspace configuration in detail (check the comments in the XML fragment):

<repository-service default-repository="repository">
   <repositories>

     <!-- ############################################################ -->
     <!-- Every repository needs a system workspace to store the JCR   -->
     <!-- configuration info as well as the version history. The       -->
     <!-- default workspace is the one that would be returned by the   -->
     <!-- login method when no workspace is specified                  -->
     <!-- ############################################################ -->
     <repository name="repository" system-workspace="system" 
                                   default-workspace="collaboration">

      <!-- ########################################################################## -->
      <!-- The first step is to define the workspace security such as the JAAS domain -->
      <!-- it applies to. It is also possible to plug a custom policy manager there   -->
      <!-- ########################################################################## -->
      <security-domain>exo-domain</security-domain>
      <access-control>optional</access-control>
      <authentication-policy>org.[..].PortalAuthenticationPolicy</authentication-policy>

      <workspaces>
        <!-- ######################################################################### -->
        <!-- Each repository can contains several workspaces, each one with a Root     -->
        <!-- Node that can have its own structure and permission configuration         -->
        <!-- ######################################################################### -->
        <workspace name="system" auto-init-root-nodetype="nt:unstructured" 
                   auto-init-permissions="*:/platform/administrators read;
                                          *:/platform/administrators add_node;
                                          *:/platform/administrators set_property;
                                          *:/platform/administrators remove" >

           <!-- ####################################################################### -->
           <!-- Each workspace can have its own way to store content but the most usual -->
           <!-- one is to use a database for the metadata information and a File System -->
           <!-- for the binary documents. Here we use a simple file system but with a   -->
           <!-- storage algorithm that store the content in a tree to split the number  -->
           <!-- of files per folder. The Swap directory is used when we upload files    -->
           <!-- ####################################################################### -->
           <container class="org.exoplatform.services.jcr.[..].JDBCWorkspaceDataContainer">
             <properties>
               <property name="sourceName" value="jdbcexo"/>
               <property name="dialect" value="hsqldb"/>
               <property name="multi-db" value="false"/>
               <property name="update-storage" value="true"/>
               <property name="max-buffer-size" value="204800"/>
               <property name="swap-directory" value="../temp/swap/system"/>
             </properties>
             <value-storages>
               <value-storage id="system" class="org.[..].TreeFileValueStorage">
                 <properties>
                   <property name="path" value="../temp/values/system"/>
                 </properties>
                 <filters>
                   <filter property-type="Binary"/>
                 </filters>
               </value-storage>
             </value-storages>
           </container>

          <!-- ###################################### -->
          <!-- Caching, Indexing and locking are then -->
          <!-- configured                             -->
          <!-- ###################################### -->
          <cache enabled="true">
           <properties>
             <property name="maxSize" value="20000"/>
             <property name="liveTime" value="30000"/>
           </properties>
          </cache>
          <query-handler class="org.exoplatform.services.jcr.[..].SearchIndex">
           <properties>
             <property name="indexDir" value="../temp/jcrlucenedb/index"/>
           </properties>
          </query-handler>
          <lock-manager>
            <time-out>900000</time-out><!-- 15min -->
 	   <persister class="org.exoplatform.services.jcr.[..].FileSystemLockPersister">
              <properties>
                <property name="path" value="../temp/lock"/>
              </properties>
            </persister>
          </lock-manager>
        </workspace>

One important point of the specification is the ability to define the structure of a piece of content, this is called a NodeType. For example, in a given company, every article that will be published on the Web will need to contain a title, an author, a summary, a thumbnail image and the article’s full text. A NodeType would be used to define each field, its type (Date, String...) and several other pieces of information such as whether the title is mandatory or not. Every created article would then have to satisfy those NodeType criteria.

A useful feature of the eXo JCR is the ability to dynamically add a new NodeType through a Java interface API. This API can be used to develop any type of application built on top of the eXo JCR; this is how the eXo ECM has been implemented.

Several other features have been added to the spec to help third-party applications build innovative services on top of JCR:

  • Native support of Dublin Core for every office document added into the JCR as any Word, PDF or Open Office document will have its properties extracted and attached to the JCR Node
  • Audit capabilities have been added to JCR Nodes and each action on a piece of content can be logged
  • Security has been enhanced and one can plug in their own security manager -- this is convenient for providing advanced profiling on document access
  • Additional event notifications which, in addition to the standard Observation feature, allow for dispatching events when persistent changes to the workspace are made. The eXo JCR also offers an extension which dispatches and fires event upon each transient session level change. This is used for the Native support of Dublin Core, for instance

Finally, we have also developed a custom storage and authentication mechanism which provides a Software as a Service (SaaS) version of our JCR repository. To do so, we have leveraged the Amazon Web Services EC2 and S3 services. EC2 allows you to instantiate a virtual machine dynamically, while S3 is a storage system over the internet. Hence if you have an EC2 and S3 account you can launch a payable Amazon Machine Instance (AMI) configured with a custom version of eXo JCR. It will use S3 to store the files and EC2 to host the database and the JCR server. The first AMI we have released also comes with a Pluggable Authentication Module (PAM) which allows you to leverage the users defined by the Linux OS.

JCR protocols

Since the very beginning of the platform’s development, we have decided to put JCR at the center of our storage strategy, which is to apply advanced services on top of a standard relational database. Hence, every application which we develop and which is a part of our product line stores its content inside the JCR. This provides a useful centralization for most enterprise data.

Therefore, access to that information from third parties applications must be straightforward. To ease that interoperability we have made the JCR repository reachable by many protocols:

  • WebDAV is probably the most popular one as it is natively supported by most Operating Systems such as Windows or Mac OS. It allows you to mount a remote server as a local partition of your file system, which then allows you to browse remote folders and documents through your normal file system interface
  •  
  • DeltaV and DASL are two RFC extensions of the WebDAV protocol. They respectively add versioning and search capabilities to the default protocol. Those are extensively used in eXo plugins like the Microsoft Office Plugin which we will introduce in the next section
  • CIFS is a Microsoft protocol to share drives over the network. eXo has implemented an abstract layer to allow any JCR repository to be seen as CIFS / Samba server
  • RMI is a Java protocol that allows you to expose Java objects remotely to other Java applications running in different JVMs. We have implemented all of the RMI stubs which allow you to expose the entire JCR API remotely
  • FTP is a protocol optimized for large file exchanges. eXo implements an FTP server on top of JCR. Files of 6 Gigabytes can be transferred using simple clients such as the one in the next screenshot:

More details on WebDAV

The WebDAV protocol is just an extension of the HTTP protocol which utilizes the PUT, GET, and DELETE methods. As we saw, the JCR specification allows you to manage structured content, however this is not the case with a standard file system, hence only a subset of the JCR semantics can be exposed through the protocol. This is usually enough when dealing with a Document Management Systems (DMS). It is interesting to note that we built the WebDAV server entirely by leveraging our REST framework.

The next screenshot shows a JCR workspace named collaboration mounted as a folder in the Mac OS file system:

Finally, to simplify the life of third-party developers, we have built some client APIs in Java and C# to model in an Object Oriented way the creation of WebDAV HTTP requests. A simple WebDAV copy method in Java would look like:

DavContext context = new DavContext("localhost", 8080, "/jcr-webdav/repository");
 CopyCommand copy = new CopyCommand(context);
 copy.setResourcePath(srcName);
 copy.setDestinationPath(destName);
 int status = copy.execute();

Exposing contents stored in the JCR through different protocols allow third-party vendors or integrators to develop custom applications which interact with the platform.

Some applications, such as Word processing, or capabilities like scanning are so common that we have also decided to directly code our own plugins to existing products.

This is the case for the Microsoft Office 2003 suite, for which we have developed a C# plugin. We have also developed a Java-based OpenOffice plugin. In both cases the WebDAV, DeltaV and DASL protocols are used. The features of the 2 plugins are almost the same and a new menu called "Remote Documents" is created. It allows you to:

  • Save currently edited documents directly on the remote eXo JCR server, and also saving in several different formats -- for instance, we support Word template documents (files with the .dot extension):
  • Support document versioning, which means that any document modification will create a new version:
  • It is also possible to compare 2 versions of a document stored on the JCR server by using the built-in Microsoft Word difference tool:
  • Utilize Full-text search to find documents already saved on the server. The search looks at both the document text and the associated metadata. The next screenshot shows the interface in OpenOffice:

With a wide range of supported protocols for accessing the JCR storage, it is quite simple to extend existing applications to connect them to the eXo content repository. Another interesting plugin (also based on the WebDAV protocol and coded in C#) is the one which was created for the Ascent Capture application by Kofax, which is a scanning and Optical Character Recognition tool (OCR). This plugin allows you to dynamically store incoming printed letters in the JCR. We also inject extracted information into the document metadata in the JCR.

Enterprise Content Management

eXo Enterprise Content Management (ECM) is a set of portlets that provide Web Content, Document and Record Management tools. It is built on top of eXo JCR and leverages the capabilities and connectors that we have introduced earlier.

The ECM product also comes with some predefined workflows that you can customize to easily share and propagate ECM content and documents within your company. You can also add your own workflow definitions and spawn them in many different ways. The workflow engine implementation itself is pluggable and we offer two implementations (jBPM and Bonita), however you can also write your own.

eXo portal integration is facilitated by a some ready-to-use presentation portlets offering many ways to display your content inside the portal either for intranet or internet/extranet use.

Thus, eXo ECM provides strong support for capturing, producing, managing, publishing and recording of enterprise content. All of this is performed in a highly customizable manner. But again the main driving force behind that product is to provide advanced functionality in an easy-to-use interface that mimics existing applications in a real operating system, such as a file explorer.

ECM File Explorer

One of the core components of eXo ECM is the File Explorer application. This portlet provides a user-friendly back-office entry point to ECM.

Drives:

The home of the File Explorer displays shortcuts to the managed repository that we call “drives”. There are three different types of drives:

  • Personal drives are reserved for each user. Documents in there can be kept private or shared with others
  • Group drives define areas which are restricted to certain user groups
  • General drives are shortcuts to other areas of the repository

Permissions can be set on drives so that users can only see drives that are relevant to their permission set. A drive can also configure many other things, such as the path location within a workspace or the views to apply inside the explorer (thumbnails, list...). The next screenshots shows the ECM administration portlet and several pre-configured drives:

File Exploring

The ECM File Exploring user interface was designed to be just as easy as managing files on your local computer. On the left, a familiar tree view displays folders. On top an address bar displays the path to the current folder. On the right, the working area shows files within the folder. A toolbar lets users manipulate content. Toolbar actions can be grouped by theme (ex: general, collaboration, search), and the UI has been tuned to provide a familiar look and feel such as the one of Windows File Explorer:

Depending upon the user’s permissions, the number of actions which are available for a given document changes. Some Web 2.0 features such as tagging, voting or commenting on a document (as shown on the next screen) can be disabled for all of the Records Management docs but enabled for the content that will be published on the web:

Several other actions also exist, from common ones such as managing versions of a document to more complex ones like checking the structure of document (e.g. what kinds of metadata are associated with it).

This portlet is the basis for any Document Management and Records Management processes as well as for the Web Content Management ones

The File Explorer allows you to easily add a Document into a File Plan, which will then become a record that will stay for a period of time in the system before being cut off. eXo ECM implements the DOD 5015.2 Records Management specification. When a PDF is uploaded, the PDF properties are extracted and bound to the document inside the JCR. Then, it is possible to perform advanced searches on this metadata and, for example, look for all the documents that have the Dublin Core "Article" value for the "subject" property. In the next screenshot, a PDF document was uploaded and the Advanced Search action was launched. The form allows us to select the Dublin Core property we would like to search. A popup will then appear which allows you to choose amongst all of the values that property has. In the screenshot, there is a unique entry in the property value list, "Article". It is also possible to combine property constraints to make even more advanced searches:

In eXo ECM, it is possible to specify the structure of a document by leveraging the JCR NodeType feature. This is done through the administration portlet (inside the "Type of content" section). Once the content structure has been created, the next step is to create a form that will allow you to create instances of that content. Such a form is called a dialog in eXo ECM, and is written as a Groovy template that is also stored in eXo JCR (and hence versionable). In the next screenshot, a form with several fields (Name, Title, Summary ...) is displayed. This form is the rendered dialog template, and each field can have one of several types (e.g. rich text editor, date, upload field...). The WYSIWYG editor allows you to import and upload images to and from the JCR repository. Once created, the structured content can be rendered thanks to another Groovy template called the view template, which simply decorates the content instance field with some HTML code. The content is now ready to be validated within a workflow process and published the web:

Actions

A major feature of eXo ECM is the ability to attach actions to any node, which includes folders. Actions are hooks to the node lifecycle (e.g. add, update, delete) which can start a new workflow or run a custom Groovy script.

The next screenshot shows the default document validation workflow that is activated as soon as a document is copied in the "Validation Request" folder. Once the document is validated, it is copied to the "Pending" folder where it waits for its publication date. When this date arrives, a job moves the document to the "Live" folder where it stays until the end of publication date is reached:

When the document is in the Live folder, third party applications or content publishing portlets just need to point to the folder, make a query to extract the last published document and to apply a nice HTML template to display it.

Actions can also launch Groovy scripts, so let's illustrate this capability with a simple script that uses the DocumentReaderService to print in the console document metadata properties such as author and creation date. Indeed, action scripts also use IoC, which ease the calling of eXo-registered services:

public class DisplayDocumentProperties implements CmsScript {

   private DocumentReaderService readerService;
   private RepositoryService repositoryService;

   // Constructor injection of needed eXo services
   public DisplayProperties(RepositoryService repositoryService, 
       DocumentReaderService readerService) {  
     this.repositoryService = repositoryService ;
     this.readerService = readerService;
   }

   public void execute(Object context) {

     // load node from JCR
     String workspace = context["srcWorkspace"];
     String path = context["srcPath"];
     Node document = (Node) repositoryService.getRepository()
       .getSystemSession(workspace).getItem(path);

     // extract document properties
     String mime = document.getProperty("jcr:mimeType").getString();
     InputStream data = document.getNode("jcr:content")
       .getProperty("jcr:data").getStream();
     Set properties = readerService.getDocumentReader(mime)
       .getProperties(data).entrySet();

     // display properties
     propreties.each() { print " ${it.key} ${it.value}" };
   } 

Scripts can be added through the administration user interface and then bound to an action and hence to a JCR Node. For instance, in the case of a publication process we could also dynamically generate an RSS feed based off of the most recently published news (this action exists natively in eXo ECM).

Business Model

The eXo Platform SAS Business Model is a traditional Open Source model which is very similar to Red Hat or MySQL. eXo provides two distributions for end users and corporations:

The Community edition can be freely downloaded from the OW2 forge. This edition is released every 2 or 3 weeks, and it contains all the latest code and commits. A basic QA process is applied on it. Testing is performed on three Open Source application servers: Tomcat, JOnAS and JBoss. The source code of that distribution is available on a public SVN server and is located in the trunk section of each module described in this article

The Enterprise edition is a stabilization of the Community edition. It lives in its own branch on the SVN server and is only available to people that have purchased an annual subscription. A release is made every 6 to 9 months for each product, and at that time the source code is tagged in the SVN server. The QA process of that distribution is an extensive one with more than 1500 integration test cases as well as stress tests. The distribution is also certified on several proprietary applications servers such as BEA WebLogic, Oracle Application Server and IBM Websphere as well as proprietary databases. The admin and user manuals are also part of this package.  Finally, add-on warranties and indemnification are applied on this distribution

eXo Platform SAS also targets two other markets:

  • The OEM market, with Independent Software Vendors (ISV) that will bundle eXo products within their applications. Dedicated licenses and royalty models are used according to customer needs
  • The SaaS one (Software as a Service) which allows you to rent eXo applications for a period of time. Technically speaking, this model leverages Amazon EC2 (which allocates some virtual machines) and S3 (which allows you to store data in the cloud)

Rate this Article

Adoption
Style

BT