eXo Platform v2, Portal, JCR, ECM, Groupware and Business Intelligence: Part 2

We have introduced the new kernel for eXo Platform 2 as well as the brand new Portal features in the first part of this article.

We have introduced the new kernel for eXo Platform 2 as well as the brand new Portal features in the first part of this article.

This second part will focus on the new products we are building and that will be available in 2006 such as:

  • Our Java Content Repository (JCR) implementation
  • The Enterprise Content Management (ECM) product
  • The Research and Development projects: t he Groupware suite with forum, message, shared calendar, wiki, project manager and more; as well as the Business Intelligence (BI) product.

Each of those products depends on the Platform one that we introduced in Part 1. Therefore, even if reading the previous paper to understand that one may not be necessary, we highly advise you to have a quick glance at it.

This second part of the article comes with the release of:

  • eXo JCR 1.0 RC2
  • eXo ECM 1.0 RC1
  • We will first detail the features of both products. We will finally introduce the eXo Groupware and eXo B usiness Intelligence that will be released a bit later in the year.
  1. Java Content Repository

In that chapter we will have a quick overview of the JCR functionalities and we will also introduce the features supported by eXo JCR 1.0 and how, if interesting, we have implemented them. For more information on JCR we invite you to directly read the specification that is very well written (probably the best one we have read so far!).

The JCR specification normalizes the storing of data in an abstract way in order to hide to the user the type of backend that is used. A good analogy is that JCR is the same level of abstraction on top of content stores (that can be FS, DB, XML Native DBs or any commercial non JCR compliant content stores on which we can provide an adapter) as JDBC is for Databases.

  • The model proposed by the specification consists of one or several repositor ies composed of one or many workspaces. Each workspace can be seen as a stor e to group content of same interest . A workspace is a tree of nodes that are used to organize and hold the content. They are characterized by properties.

Of course JCR comes with higher levels of service such as versioning or locking but its main purpose is to enable read and write operations in a normalized way as well as the creation of structured contents. Those features are described in the two first levels of the specification. Our implementation supports all functionalities of level 1 and 2 as well as all the optional features except the JTA support (at the time of this writing!).

We are currently running the TCK tests and – once again at the time of this writing – we have passed more than 90% of the tests overall. You can find a summary table of the TCK results at the end of this section.

Note that all the functionalities such as template creation and management, scripting, publication, validation workflows and data transformation are out of the scope of the JCR specification and are part of the ECM product that we will describe in the next chapter.

A) Level 1

As shown in the next image (taken from the Reference Implementation documentation), level 1 focuses on read functionalities, which includes XPath API for searching , as well as structured documents description thanks to NodeType Definition.

a) Access

The main entry point to any JCR implementation is the Repository object. According to the implementation there can be several ways to lookup the object but the most usual way in standalone environments is to use a JNDI server such as in the following code:

InitialContext jndiContext = new InitialContext();

Repository repository = (Repository)jndiContext.lookup("repository");

With eXo JCR, it is also possible to leverage our service container and lookup the service (or have it injected if your component is also located in the service container) using the following Java code.

PortalContainer container = PortalContainer.getInstance();

RepositoryService repositoryService = (RepositoryService) container.


Repository repository = repositoryService.getRepository()

Using this way brings more flexibility. For more information on the PortalContainer please refer to the first article part.

Then, a user needs to login into the server in order to get a Session object. There are two main ways to log in, one by creating a Credential object such as:

Credentials credentials = new SimpleCredentials("exo", "exo".toCharArray());

Session jcrSession = repository.login(credentials, "production");

Or if you run an implementation of eXo that is for example embed ded in the portal , you can then directly login using:

Session jcrSession = repository.login("production");

Indeed, in embed ded cases, the implementation will directly leverage the organization and security services that rely on LDAP or DB storage as well as JAAS login modules. Single Sign On (SSO) products can now also be used as version 2 of the platform support s them natively.

b) Document structure: NodeType and MixinType concepts

The NodeType concept is probably the most complex to grasp but it is also the most powerful and useful one. The idea is to define a type that will describe the structure of the nodes that are of this type. This is almost the same type of relationship that there exist between a class and an instance (apart that the NodeType can not contain business logic methods).

You could for example create a NodeType named “exo:article” that would define what a Node of this type should contain as properties (meta data or real content) and what should be the type of its child nodes (node of type “exo:image” for example). Each node that will be created and that will be of type exo:article will then have to follow the constraints defined by the NodeType. That, in this particular case, can be a property for the name, one for the summary, one for the article content and a collection of children that will contain the images or attachments.

When a Node instance is created its NodeType is affected. If no specific String is used to define the type, then the implementation will try to resolve the type according to the node name and its parent constraint s and if it can not resolve the type then the default “nt:unstructured” NodeType is used.

Node newNode = parentNode.addNode(nodeName);


Node newNode = parentNode.addNode(nodeName, “exo:article”);

There also exist s the concept of MixinType, which allows a Node to get more constraints on it according to what the MixinType defines. If we use the same analogy, a MixinType is equivalent to an interface while a NodeType is equivalent to a class. Therefore, we could define the MixinType "exo:published" which would force any node of that type to define two new properties such as the publication start date and the publication end date.


newNode.setProperty(“exo:startPublication”, startCalendar);

newNode.setProperty(“exo:endPublication”, endCalendar);


When saving, if the two properties were not filled, then a constraint exception would arise.

As you can see a MixinType is just a complement to a primary NodeType.

Note that eXo ECM defines the “exo:article ” NodeType and the "exo:published" MixinType . We will review them and how they are used in the next chapter.

c) Exporting

Any application that supports JCR level 1 must also support the export functionality that can be quite useful for portability purposes, as any exported part of the content hierarchy will be exported as an XML document that can then be imported in any JCR level 2 compliant implementations.

A usual use case for import is to upload thanks to a web application (of course that can be a portlet) the XML content to “mount” at a special node path. The following code is a sample of one of our ECM portlet that allows browsing any workspace. For each node we view, we can import or export the sub tree. The next code shows how simple it is to import some content we have uploaded.

byte[] content = uiupload.getContent() ;

try {

session.importXML(node.getPath(), new ByteArrayInputStream(content),


} catch (Exception e) {

JCRExceptionManager.process(iprovider, e);


The UIUpload component is a JSF one whose goal is to render an upload HTML field inside a multipart form and to extract and wrap the uploaded result so that we can simply get it with the method uiupload.getContent().

The JCR API provides the interface ImportUUIDBehavior that defines how the implementation should behave when the XML tree contains nodes with UUIDs that conflict with the UUIDs of nodes that are already in the repository. The four properties are talkative enough and we will not describe them more.

public interface ImportUUIDBehavior {

public static final int IMPORT_UUID_CREATE_NEW = 0;

public static final int IMPORT_UUID_COLLISION_REMOVE_EXISTING = 1;


public static final int IMPORT_UUID_COLLISION_THROW = 3;


d) Searching

For searching purposes the specifications level 1 defines a Query mechanism that leverages the XPath syntax. Repository implementations can also support SQL syntax but that feature is non-mandatory. eXo JCR also supports SQL type search and its use is very similar to the one we will describe for XPath, only the syntax changes.

To create a query one must first get the QueryManager from the Workspace object such as in the following code:

QueryManager queryManager = session.getWorkspace().getQueryManager();

Then in case of XPath search we can use a statement such as “/jcr:root/path/of/your/node//*” , that will look for all the items under the path /path/of/your/node/. Then, we create a Query object by passing the previous statement and the query type, here Query.XPATH, as the arguments of the createQuery() method of the QueryManager object.

Query query = queryManager.createQuery(statement, Query.XPATH);

Note that the Query object can be persisted in the JCR itself if the implementation supports it and eXo JCR does. That can be useful for example within an ECM tool , where an admin can define a set of complex preconfigured Queries that the normal user can directly use as preconfigured ones. The following code fragment stores the Query at the specified path.


Indeed he JCR API defines a Query NodeType that we can visualize in our ECM browser.

Once we have created the Query object we just have to execute it to get a QueryResult object in return and a call to getNodes() method to obtain a NodeIterator as shown in the next code fragment:

QueryResult queryResult = query.execute();

NodeIterator iterator = queryResul t.getNodes();

The next screenshot shows the result page in our JCR browser portlet part of the ECM product. By clicking on the content link , you can select a result and directly go to the corresponding node path in the explorer.

B) Level 2

Level 2 is mainly about write operations while level 1 was about read operations that can be seen as export functionalities.

It also introduces the notion of access control with 4 permissions (add node, remove node, read node, set property) and some security methods.

The next image shows the security screen in the JCR browser portlet where you can view all the permissions that are applied to a node. In that particular case we have all the members of the group “/admin ” (*:/admin) who can view, add a child node, set a property or remove an item. The user “exo” has the same permissions.

If you wish to add permissions and if you have the right to do so, you will be redirected to the following form, which lets you select your user or group and the permissions to apply.

In eXo JCR, the security leverages the SecurityService (based on JAAS and SSO) as well as the Organi zationService model (memberships in groups) and its different implementations (DB or LDAP). Therefore, it is possible to bind a node with a user or a group of users that have the same membership in a group. That binding, which is done by adding a MixinType of type “exo:accessControllable” to the node, will define the security policy for all children nodes.

We also have extended the API support with some advanced interfaces such as:

public interface ExtendedNode extends Node {

void setChildrenPermissions(Map permissions)

throws RepositoryException, AccessControlException;

AccessControlList getChildrenACL();

void clearChildrenACL() throws RepositoryException, AccessControlException;

void removeChildrenPermission(String identity)

throws RepositoryException, AccessControlException;

void setChildrenPermission(String identity, String[] permission)

throws RepositoryException, AccessControlException;

void checkChildrenPermission(String actions)

throws AccessControlException, RepositoryException;


where AccessControlList is a class that contains information on the node owner as well as a Map of permissions applied to that node among the four previously described ones.

The other methods and returned objects are talkative. So if you use eXo implementation a simple cast to that interface will allow you to use those methods.

C) Level 3

What we call level 3 is in fact all the functionalities that are not mandatory in level 1 or 2. That includes some important features such as locking and versioning but also a normalized Observation model.

a) Observation model

The Observation model is an important one especially in the ECM context where content need to be stored but also managed, moved, transformed…Our validation workflow process in our ECM product is for example based on that mechanism but we will describe the more generic concept of document Actions in the next section.

The Observation allows you to register listener objects that for example can be executed when nodes of certain types are added at a specified location. As defined in the Event interface there are 5 types of events that can be fired by observation mechanism:

NODE_ADDED, NODE_REMOVED, PROPERTY_ADDED, PROPERTY_REMOVED, PROPERTY_CHANGED. That manipulation is done thanks to the ObservationListener object as shown in the next code fragment:

ObservationManager obsManager = workspace.getObservationManager();

if (ActionServiceContainer.ADD_PHASE.equals(type)) {

obsManager.addEventListener(listener, Event.NODE_ADDED, srcPath, true,

null, null, true);

} else {

obsManager.addEventListener(listener, Event.NODE_REMOVED, srcPath, true,

null, null, true);


The last four arguments of the method are:

    • Boolean isDeep: which tells if the we should listen for the node to be added or removed in the entire sub tree .
    • String[] uuid which tells that the event will only be launched if the parent node of the node we add or remove has an id in the array.
    • String[] nodetypes which tells that the event will only be launched if the parent node of the node we add or remove is of the type of one NodeType name located in the array.
    • boolean noLocal that tells that the modifications made through the current session will not launch an event.

b) Versioning

The versioning part of the specification is quite complex and relies on several concepts of the JCR API such as the MixinType or UUID ones. Its goals are to manage a graph of versions to enable the restore of previous versions, the creation of branches as well as their merge.

Making a node versionable is a very simple operation, which consist of adding a MixinType.


The first time a node is made versionable, it gets automatically the status of a checked out node. Any modification on that node will be made persistent when the changes are saved and when the node is checked in. Another version object will then be created.

In the next screen we see (green arrow) that the PDF document invoice3.pdf (stored as a nt:file node) base version is the 5 th one and that its status is checked in.

Checking in and out a Node are also very simple tasks.

Version version = node.checkin();



If the node itself is not versionable but if one of its ancestors is and if that one is checked in, then no write modification will be allowed on the child node. To allow write changes, one will first have to checkout the ancestor node.

The next screenshot shows the version tree of a Node in our ECM JCR browser portlet. The version number name works in our implementation like the SVN ones. It is possible to restore, view or even compare different versions of a node that has the type nt:file (even if it is a binary one and its MimeType is supported by the DocumentService , as we introduced in the first part of this article).

All the information of a version is accessible through the VersionHistory object binded to a versioned node. Getting that objects is trivial.

VersionHistory vH = node.getVersionHistory();

Then you can lookup the version you wish thanks to several methods such as the getRootVersion() or the getBaseVersion().

Each versioned node points to a VersionHistory at the /jcr:system/jcr:versionStorage path. Each version history object contains all the Versions of the Node (strictly speaking of the set of corresponding Nodes) and each Version object has a pointer to its predecessor or its successor and contains the frozen Node state. That way it builds a graph of versions as seen in the next image taken from the specification itself.

c) Locking

Locking a node allows you to make it only modifiable by you, usually for the time of your session.

As for versions methods, making a Node lockable is done through the use of a dedicated MixinType.

if(!node.isNodeType("mix:lockable")) {




node.lock(true, true);

with lock(boolean isDeep, boolean isSessionScoped) ;

In our example (which is also the default implementation for locking in our ECM portlets), the node lock is deep and session scoped, in other words no modification on the children are allowed for the time of the user session. When the session expires, the lock is disabled.

D) Advanced functionalities

a) Container and workspace configuration

eXo JCR is based on the same IoC container architecture as the rest of platform. Both top-level containers (which can be PortalContainer or dedicated StandaloneContainer)

and internal (RepositoryContainer and WorkspaceContainer) ones are subtypes of ExoContainer.

Our implementation can be configured to use several repositories and each repository according to specification can have several workspaces.


Here you can see fragment of JCR service configuration reflect ing its architecture:

<repository-service default-repository="repository">
<repository name="repository" system-workspace="production">
<workspace name="production" auto-init-root-nodetype="nt:unstructured">
<container class="org.exoplatform.services.jcr.impl.storage.rdb.container.SingleRDBWorkspaceContainerImpl">
<property name="sourceName" value="default"/>
<cache enabled="true">
<property name="maxSize" value="5000"/>
<property name="liveTime" value="30000"/>
<query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
<property name="indexDir" value="../temp/index"/>

As you can see, repository service configuration is pretty simple and self-explanatory.

eXo JCR can be configured to use one or more repositor ies that can be called using getRepository(String repositoryName) or just getRepository() (for default one) using both container or JNDI mechanism as explained above.

Each repository may have one or more workspaces, which will contain specific data container and other components for data access. Note that each repository should have one system workspace to store some system data like version storage, nodetypes and namespaces.

Components that need to be configured are exposed in exo-jcr-config.xml file. As you can see from the example above there is a repository named “repository” with system workspace called “production” that is initialized during startup with root node of type “nt:unstructured”. This workspace has relational database based backend of type

org.exoplatform.services.jcr.impl.storage.rdb.container.SingleRDBWorkspaceContainerImpl (see below).

There are also configuration for workspace Cache and Query Handler.

b) Register NodeTypes

JSR-170 does not specify mechanism for node type registration so we added registration mechanisms exposed in ExtendedNodeTypeManager interface that extends standard NodeTypeManager.

It allows to register node type using dedicated Java class, object and also special type of bean called NodeTypeValue (that can be used in dynamic registration) or thanks to a declarative way using an XML Input stream.

An XML Node type definition is just translation of spec’s definitions to XML. For instance nt:unstructured node type can be defined like:

<nodeType name="nt:unstructured" isMixin="false" hasOrderableChildNodes="true" primaryItemName="">
<propertyDefinition name="*" requiredType="undefined" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="true"/>
<propertyDefinition name="*" requiredType="undefined" autoCreated="false" mandatory="false" onParentVersion="COPY" protected="false" multiple="false"/>
<childNodeDefinition name="*" defaultPrimaryType="nt:unstructured" autoCreated="false" mandatory="false" onParentVersion="VERSION" protected="false" sameNameSiblings="true">

c) Workspace Data Containers

Java Content Repository API offers a fa cade for accessing data regardless of data storing mechanism. It can be for instance local or remote file system, relational database, XML native database etc.

Our implementation offers simple internal API to plug any type of backend. The main components to do so are the WorkspaceDataContainer – an abstraction object for wrapping data source - and data storing components NodeData and PropertyData.

Implementing these interfaces eXo JCR can be extended with other type of data storage. All you need to point workspace to use specific data container is set container type and some container specific parameters if necessary like in example above:

<container class="org.exoplatform.services.jcr.impl.storage.rdb.container.SingleRDBWorkspaceContainerImpl">
<property name="sourceName" value="default"/>

For the time being eXo platform has two type of Hibernate based data containers (see org.exoplatform.services.jcr.impl.storage.rdb.container.*) .

d) WebDAV support

The WebDAV protocol allows you to use third party tools to communicate with hierarchical content servers through HTTP. It is possible to add, remove documents or set of documents from a path on the server.

The DeltaV protocol is an extension of WebDAV that allows to also manag e document versioning that we will support in the future.

In eXo JCR we plug the WebDAV layer – based on the code taken from the extension modules of the reference implementation - on top of our JCR implementation so that it is possible to browse a workspace using the third party tools (can be Windows folders or Mac ones as well as a Java WebDAV client such as DAVExplorer as used in the next screenshots).

By default, the WebDAV server will allow the access to the Draft workspace that is preconfigured. Of course that information is specified in the WebDAV eXo service configuration, as shown in the next XML fragment and can therefore be easily changed.

Defines how a missing authorization header should be handled.
1) if this param is missing, a 401 response is generated.
This is suiteable for clients (eg. webdav clients) for which
sending a proper authorization header is not possible, if the
server never sended a 401.
2) if this param is present, but with an empty value,
null-credentials are returned, thus forcing an null login
on the repository
3) if this param has a 'user:password' value, the respective
simple credentials are generated.
<!--property name="missing-auth-mapping" value=""/-->
<property name="workspace" value="draft"/>

A great use case for the WebDAV is when you would like article writers who use Microsoft Word to create and publish their documents. Thanks to WebDAV, they can easily upload those docs to the JCR. At that time, several operations can be executed such as a validation workflow launch before some publication. We will see a real example of such a use case when we will introduce the ECM functionalities.

When accessing the WebDAV server, here thanks to the URL localhost:8080/cms/repository, the user will be asked to enter its login and password. Those will then be checked using the organization service (that can be implemented thanks to a DB module or thanks to a LDAP one) and the JCR user session will be created with the correct JCR Credentials.

Once mounted, the repository will be browsable as any other hierarchical set of directories and files. According to the third party tool that is used, it will be possible to add and remove the directories and/or files.

The next screenshot shows the path /cms/home/users/ in the draft workspace. Those are indeed preconfigured folders and are used in the ECM product in order to dynamically create a JCR home directory for all new users.


The next table concludes the JCR section. It gives a status of features and their compatibility with the specification:

eXo JCR features map and test results (Dec 31, 2005)

JUnit test results are aggregated and summarized

* eXo JCR test suite

** TCK test suite


EXO test*



Level 1 features

Repository access







Exo organization service’s realm, JAAS based

Session read methods




Workspace read methods




Node/Property read








Session namespaces registration/remapping




Check permission




References/UUID reading




Multiple workspaces




Export Doc/Sys View




Node Types




Xpath query




Level 2 features

Node adding




Property/Value setting/adding




Remove items




Assign/remove mixin node types




Import Doc/Sys View




Namespaces registration/remapping



Namespace unregistration is not supported





Node Type registration



Supports node type declared as object, class, value object and XML.

Node moving/copying




Node cloning




Node same name sibling




Orderable child nodes




Optional features

JCR-SQL query




Query persistence




External transaction








Versionable assigning




Check-in, Check-out




Version restore




Version merge




Observation (events)



In progress

Proprietary features

Multi-repository configuration



Exo Portal Embedded and Stand-alone

Set permission/ownership




  • The Enterprise Content Management

A full feature ECM platform should address several functionalities of the 5 fields:

  • Document capture (a): how to move content into your content repository?
  • Document storing (b): where do you put your content and how to find it again?
  • Document management (c): what are the tools and techniques for moving content around an organization and monitoring those tools performance?
  • Document publishing (d): how do you get the right content to the right audience on the right device?
  • Document backup (e): what are your options for long term archival and storage of your content?

A) And what about eXo ECM 1.0?

The goal of eXo ECM is to provide as much functionality in each area to provide Open Source alternatives that rely on Open standards to proprietary solutions such as Documentum or Interwoven ones.

In eXo Platform version 1, we provided a basic Content Management System (CMS) solution based on the JCR specification draft implementation we had at that time. But we did not have any other features in the other areas apart some limited web publishing (d).

With version 2 we go further the Document storing (b) and also provide Management (c) and Publication (d) functionalities as well as some basic capture (a) and backup (e) ones:

  • XML format (as defined by the JCR API and introduced in the previous section), submit web forms that are generated thanks to the document structure (see dialog templates for more explanation) or upload content thanks to WebDAV (also described in the JCR section). The XML import is an important one as thanks to Extract, Transform and Load tools (ETL) it is possible to inject documents that were loaded from several different types of devices such as scanners.
  • Storing: the eXo store is relying on our JCR implementation presented in the previous section. The default real store location is a DB one. In mid term we will provide several other back end implementations that can act as connectors to other CMS or Data Warehouses. In all cases, those contents will only be accessible through the normalized JCR API. Searching, locking, versioning as well as security functionalities are part of the store ECM layer.
  • Manage: that layer is the one that add s the most value on top of the Storing one as it contains all the techniques to share documents in the Organization. Our ECM implementation includes a set of powerful portlets to view, create, move and monitor structured and unstructured documents all other the JCR workspaces. In that implementation, it is mandatory to bind the JCR NodeType concept with templates that will dynamically build the forms to create new nodes or render the already created ones. We have also introduced the concept of “Document Lifecycle Actions” that allows a custom action (that can be a Business Rule, a Groovy Script or a Business Process) to be launched either when the document is newly added, removed or viewed. That model allows for example to manage advanced document validation operations as well as ordering document publication and backup at dedicated dates. Furthermore, thanks to the use of portal communities that can manage pages with ECM portlets, it is very easy to address collaboration and document sharing among the same groups.
  • Publish: web publication is of course a very important functionality and we do provide a display portlet that points to JCR directories, extract the children and render them using the previously introduced templates. That way contents can be see n in the company intra or extranet as well as on mobile devices as the portal supports them. The Action concept also allows providing a mechanism to publish content through interesting channels such as email. Furthermore, thanks to the JCR export functionality, it is possible to create a XML file out of a document tree and to send it to partners. WebServices can be used in this scenario. We will support some other XML syntaxes such as RSS and plain RDF as soon as possible.
  • Backup: critical documents and information must be preserved in safe places, usually in different physical location as the other data and on long life hardware. Of course eXo does not cover the hardware ECM part but allows the abstraction of them thanks to JCR workspace. Indeed, by introducing a Backup workspace built on top of a different data sources and by populating it thanks to the Action concept we insure data preservation.

Therefore we have decided to change the name of that CMS prototype to release an ECM product based on top of our JCR certified and optimized CMS implementation.

Furthermore, the large number of Web Content Management Systems (WMCS) that are usually also named CMS products (check the CMS matrix web site to see the confusion), and to which eXo was in first glance similar, do not cover many pieces of the ECM puzzle.

B) Learning by doing: Upload, Version, Validate and Web Publish a document to finally back up it.

To illustrate several of our ECM most important features, we will go through an entire document lifecycle, from its upload thanks to WebDAV to its backup.

a) Use WebDAV to upload a document

In the JCR section we have already used DAVExplorer to connect to the draft repository. In that section we do the same and upload the following – very simple - Microsoft Word document , called “document1.doc”, to the user home directory. Remind that each user has its own directory that is created when the user is added.

Doing so through with DAVExplorer is simple too.

Once uploaded, we can check that the document has been added through the JCR explorer portlet.

To do so, login as admin and go to the ECM portlet page. That one contains two tabs, one that displays the workspaces and allows you to browse them and an admin tab that we will review a bit later.

The Word document has been uploaded in the draft workspace under the “exo” home user directory.

When using WebDAV, file resources are then stored in the JCR using the predefined nt:file NodeType as shown in the next screen. That NodeType must have a child named jcr:content that can be of any type.

To view the NodeType definition of the current node in the ECM explorer, just click on the last button of the toolbar.

In our example that jcr:content child is of type nt:resource and that is quite often the case.

To view the nt:resource NodeType definition, we will need to enable an advanced functionality of our ECM portlet. Indeed, by default, when clicking on a node that has a view template associated with it, then the template is used and the child list of the node is not rendered as we see on the next screen that render s a download label for the DOC document. Note that this view template is the one seen by the admin only (label ADMIN VIEW) which means that we can provide several customized dialog or view templates, each one bound to a dedicated membership and group.

To change that default rendering policy you just need to click on the preferences icon on top left.

By clicking on the check box you will enable the JCR like view policy . This view is intended for advanced users. The portlet will render list of children of any nt:file document instead of using its view template.

If you click on that jcr:content node you will see that it does not contain any child. By viewing its Node definition we can see that it defines several mandatory properties such as the mime type of the resource, its encoding, its creation date…

As a side note, you probably have been interested by the other functionalities of the preference form. Indeed it allows you to choose among several views (List, Thumbnails and Mac) as well to define the document sorting algorithms (by type or by alpha). Here is the Thumbnails view and we let you discover how the Mac view looks like!

b) Create a dedicated folder and move the file into it

Creating a new folder is a simple task as we have added a dedicated button and form to do it. In the JCR API, adding a folder is simply adding a node of type nt:folder and we could have made a generic form to manage it. But we wanted that portlet to be user friendly and we have abstracted by default the JCR API as much as possible when we though t it was too complex for basic users who do not care of the complex underneath implementation.

To copy the node one must use the list view and click on the “copy” icon located at the same line of the node and then uses the “paste” icon on the newly created folder.

Note that to persist any change, we need to either save the parent node or the global session by using the different floppy icons.

c) Transform the document to text

It is possible to do the next steps using directly the Microsoft Word document but we will work on the extracted text and then submit – for validation and publication - an online revised content.

Extract raw text from a word document is not a common action and to support it we added a custom groovy script that is launched when the user – who has the correct permissions – clicks on the dedicated custom action link in the last column.

We have already introduced the concept of action a bit before. In that particular case we have a Script action that is tied to the Read phase of the document lifecycle. Therefore the action can only be executed when a user browses the explorer and decides to launch the script. The script is written in groovy language and is directly stored in the JCR so that it is editable online.

Therefore we will first create an action instance of predefined type “exo:transformBinaryToTextAction” for the newly created folder. That action will then allow the user to transform to text all the binary children files located in it.

Adding an action is a simple task, you just need to have the write permissions on the node and to select among all the available ActionType. Several action instances can be bound to the same node as this is by default the case of the /cms/publications/en/news node in the draft workspace.

Read actions of a node are viewable in the custom actions column of the list view (if the user has the rights). Then by a simple click on that link you will activate the action, here the transform binary to text script.

Note that all the steps, like creating the Groovy script, the ActionType it refers to and the templates, are doable online by the admin. We will not describe them here as the “exo:transformBinaryToTextAction” ActionType is part of the ECM distribution.

All binary files, here Document1.doc will then be transform ed and a Document1.doc.txt will be produced out of it as seen in the next screen.

With that extensible Action mechanism, that we will review also when talking about document validation when a workflow is launched, it is very easy to plug your own business logic and to modify it by editing the script online.

d) Version the node, lock it, edit it and check in/out the modification several times

We will then work on the text version of the document. The work in this section will consist in modify ing the text after locking it so that you are the only one to be able to do that modification, version ing it, modify ing the new versions, compar ing the versions and then restor ing an older one.

      • Locking a node is a very simple task that simply requires you to click on the lock icon in the view list. As said in the JCR introduction session, that lock is a deep one (aka sub nodes are made read only too) and only lives for the lifetime of the session. To unlock the node just click on the barred lock icon.

      • Modify ing a nt:file node is also easy, you just have to click on the pencil icon in the list view. If the jcr:content child node of the file is of type nt:resource then we check for the mime type of the file. If that one is starts with text then a simple form with a textarea is used to modify the text online. (A WYSIWYG editor will also be available for online editing). If not, then an upload form is displayed. Saving the modifications is done through the floppy icons as stated before.
      • You may want to do some further modifications but you are not sure about them and you would like to be able to roll back those changes later. To do so we will version your node, in other words any modification that has ever been made will be persisted and it will be possible to restore the old state of a document. Once again the user interface to do so is pretty simple. When viewing a node, you just need to click on the manage version icon of the toolbar.

If the node is already versioned then you will be able to see the version graph, if not, a label will allow you to version the node and then see the graph.

      • Once a node is versioned, it is only possible to make modifications on it when it is checked out. The first time a node is versioned its status is already “checked out”. Green arrows are visible when a node is versioned and allow you to checkout and checkin a node. Each time a node is checked in a new version is created and the old one is persisted.

      • If the versioned document is of type nt:file, then it is possible to compare 2 versions and see the differences (per line) between them.

e) Copy the document to the publication folder in the draft workspace in order to ask for validation before publication

Once you think that your base version is ready for publication you will have to copy or move your document to the path /cms/publications/en/news in the draft workspace. Of course, if the document is not in English you can also copy it in the dedicated language folder.

By default there exists two publication folders that are news and events. Those are pre configured in the CMS service configuration.xml file (refer to the first article for more information on that XML file).

The publication folder in the draft repository has two actions bound to it (as seen in the next screenshot):

      • One “send mail” script action bound to the READ lifecycle phase of the document, exactly like the transform binary to text action we seen just before. It will simply send a mail when the custom action link is clicked.
      • One “publication workflow” business process action bound to the ADD lifecycle phase of the document. In other words, when a document is added in a sub node of the publications directory, a JCR Observation event is thrown and the ECM system – that listen to it – will start a Business Process. In that case, the publication workflow action will trigger a ContentValidation business process that contains one main Activity (or business process state). The people that will be in charge of validating that content are all the members of the group /company/direction

Therefore, if we copy the Document1.doc.txt to the news directory the validation process will be activated. Copying the node is easy, as you simply need to click on the copy icon in the view list and then on the paste one on the top right corner of the toolbar.

Note that the choice of directories for publication is configurable and you can provide several folders bound to different actions that will move the node document to different places. Same for the validators and even the business process graph can be modified for your own needs and business practices.

f) Validate content and monitor business processes

By copying the document in the news directory, we have activated the validation workflow process and a task is now waiting for a member of the group /company/directors. The admin user is a member of that group.

To check that the process started we can go to the business process monitoring portlet that only the admin can see (next screenshot). That portlet contains two tabs, one that show the status of all the current versions of the deployed processes, the other one that show the timers waiting for a task to complete or to be activated.

The edit mode of that portlet contains a form that allows uploading a new business process archive or a new version of an already deployed one.

If we click on the content validation process we will see that a process instance is started but not completed yet. It is also possible to get more information on the instance history such as the activity that were completed, the end date and who completed them. In the next screenshot we can see that the evaluation activity is not yet resolved and that we are waiting for a member of the group /company/validators to take care of it.

The admin user is a member of that group, hence when he visualizes its normal activity Task List he will see that task waiting for him. That user portlet also contains two tabs, one that shows the process that can be started (some processes can not be started in a dedicated portlet and are not shown in the generic task list portlet) and the tab of the user task list.

We also append to that list all the tasks that are bound to the groups the user is in.

In the next screenshot we see that we can manage the evaluation task.

The Validation Content Business Process is quite a simple one with few Activities. Basically, the content can be validated and then the document is copied to the production workspace, it can be disapproved (and a the document creator will then see a task asking for changes in its personal task list), refused (the process ends) or delegated to an individual or a group of people (technically this will launch a recursive sub business process, as many times as we have delegations).

Furthermore, you can select the publication start date and the publication end date from the activity form. In other words, once validated, the document will only be copied in the production workspace and therefore being web published only when the publication start date is due. When the publication end date is reached the document will then be moved to the backup workspace and will therefore not be web published anymore. In both cases we launch timers that are viewable in the previously introduced admin workflow portlet.

The WorkflowService implementation has been abstracted in eXo Platform version 2. Indeed in version 1, it was dependant of the JBPM BP engine, but in version 2, no reference of any implementation class is used in the client code. Therefore the workflow implementation can still be JBPM but other Business Process Engines can be used. This is currently the work we do with the ObjectWeb Bonita team ( http://forge.objectweb.org/projects/bonita).

Note that the document to be validated is displayed in the form shown in the next screenshot. It uses the view template we have introduced and it uses the template that is bound to the user role; in that case the Admin view template (that is the reason why you get the “ADMIN VIEW” label). Once again, you can customize that template online – if you are the admin - as those are directly stored in the JCR.

g) Visualize the published content during the publication period

Once validated, the content is moved from the draft workspace to the production one. You can double-check it by log ging as the admin user and brows ing the production workspace.

We already said that there exist multiple publication channels such as Web Publication, XML, RDF, RSS… We provide a simple mechanism for web publication thanks to the DisplayDynamicPortlet that is part of the ECM stack. That portlet allows us to reference and render documents located in a dedicated path in the JCR production workspace.

By default, the ECM home page contains the news portlet that points to /cms/publications/en/news directory of the production workspace. So to check if the web publication is a success just log out from the admin user and you should see the document in the news portlet. According to the portlet layout in use, you will either see the document titles as a list or in tabs (other layouts can be easily created).

As an admin if you think that an older version of the document should be published th en try to restore one and check once again in the display content portlet which text is rendered.

h) Check that the content has been backup

If you set up an end publication date and that the document is currently being web published you should be able to see when the backup timer is due in the admin workflow portlet.

When the publication period is due, the document will be moved to the backup workspace and won’t be viewable from the display dynamic portlet anymore.

Remind that in eXo JCR, each workspace can have its own data source. Therefore, for physical security reasons, the backup service should be located in another DB or file system as the draft and production workspaces.

C) Admin tasks

We have already seen the Workflow admin part. In the future we may integrate the workflow monitor portlet with the JMX one we introduced in the first article.

The ECM admin portlet allows you to modify the templates, the scripts and rules as well as creating new Action types.

a) Templates

A template is a velocity script used to produce some HTML code. It can be used either for generating a form associated with a NodeType (dialog template) or for displaying a view of a node instance (view template).

In eXo ECM we provide several couple of templates for different node types as shown in the next screenshot.

Each NodeType that has been bound to the template couple is called a DocumentType. Each of those has a default dialog (named dialog1) and view (named view1) template. Those default templates are bound to the role * which means that any user can use them when viewing a Node or NodeType.

- View templates are simpler to understand; actually the idea is simply to render some HTML with information stored on a JCR Node object. The next velocity code fragment that render s the view for a Workflow Action Node shows how simple it is. The Node object is looked up from the JSF UI component and then directly manipulated as described in the specification.

#set($node = $uicomponent.getNode())
<span>To Workspace:</span>
<span>at location:</span>

- Dialog templates are a bit more complex but not that much. The goal of them is to dynamically create a n HTML form with several types of fields (text, textarea, select, upload, checkbox fields…) and to associate them with a property of a JCR node when the form is submitted.

To do so we use velocity directives, which allows plugging extensions into the velocity scripting language. Those directives will allow dynamically creating JSF components and adding them as children of the current UI component, which is a multipart form. Once the form is submitted, all the components value are decoded thanks to JSF and then we can invoke the CMS service to create the node according to the mapping of the field and the relative path of the property. The next code fragment shows the most simple dialog form.

#jsfDialogFormField("inputName=hiddenInput1" "jcrPath=/node/jcr:content" "nodetype=nt:resource" "visible=false")
#jsfDialogFormField("inputName=hiddenInput2" "jcrPath=/node/jcr:content/jcr:encoding" "visible=false" "UTF-8")
#jsfDialogFormField("inputName=hiddenInput3" "jcrPath=/node/jcr:content/jcr:mimeType" "visible=false" "text/html")
#jsfDialogFormField("inputName=hiddenInput4" "jcrPath=/node/jcr:content/jcr:lastModified" "widget=date" "visible=false")

<div class="title">File</div>
<div class="detail">
<div class="row">
#jsfDialogFormField("inputName=name" "jcrPath=/node" "editable=false" "visible=if-not-null")
<div class="row">
#jsfDialogFormField("inputName=summary" "jcrPath=/node/jcr:content/jcr:data" "widget=textarea")

The first four lines allows us to create hidden components with pre configured values such as in that case the file encoding (UTF-8) or the mime type (text/html).

Then it comes to the HTML generated part. The widget value tells what type of JSF UIComponent should be used and hence what will be the generated HTML. The “jcrPath” directive attribute tells to which location the field value should be stored. That way it is possible to create a complex dynamic form that will end into the creation of a JCR node.

More advanced functionalities are available such as the possibility to plug a groovy script to one field. That way it is for example possible to dynamically fill a select box field with dynamic entries such as in the next code line taken from the dialog template used to create a calendar event.

<div class="row">
<label>Category : </label>
#jsfDialogFormField("inputName=categories" "jcrPath=/node/exo:category"
"widget=selectbox" "script=FillSelectBoxWithCalendarCategories.groovy")

The FillSelectBoxWithCalendarCategories.groovy is a simple script that will query the calendar service to get all the available categories and then will fill the select field with it.

Furthermore it is also possible to bind an advanced JSF UIComponent to the field in order to allow more complex selections. That is for example the case when using the workflow publication action form where a permission selector component has been bound to the validator field. In that case a select icon is appended after the field and when you click on it the usual membership/group selector component will be rendered.

#jsfDialogFormField("inputName=validator" "jcrPath=/node/exo:validator" "selectorAction=selectValidator"

The icon can be customized too and looked up, thanks to the use of the @ character in the previous code, directly from the portal resource bundle.

More advanced functionalities are available for dialog templates but we will not describe them there and we invite you to refer to the documentation or to ask questions on our forum.

Both type of templates can be created and edited online.

As for any business logic in eXo Platform, the template methods are exposed through an interface service that allows you to programmatically manipulate templates as shown in the next code fragment. The JCR API is used, and it is either possible to lookup the path location in the production workspace or to directly extract the content of the template with the getTemplate() method.

public String getDefaultTemplatePath(boolean isDialog, String nodeTypeName) ;  
public String getTemplatePath(boolean isDialog, String nodeTypeName) throws Exception ;
public String getTemplatePath(boolean isDialog, String nodeTypeName, String templateName)
throws Exception ;
public String getTemplate(boolean isDialog, String nodeTypeName) throws Exception ;
public String getTemplate(boolean isDialog, String nodeTypeName, String templateName)
throws Exception ;
public void addTemplate(boolean isDialog, String nodeTypeName, String templateName, String[] roles,
String templateFile) throws Exception;
public void removeTemplate(boolean isDialog, String nodeTypeName, String templateName)
throws Exception;
public boolean isNodeTypeConfigured(String nodeTypeName) throws Exception ;
public NodeIterator getDocumentTypes() throws Exception ;
public NodeIterator getTemplates(boolean isDialog, String nodeTypeName) throws Exception;

The last methods allow you to get some information on which DocumentTypes have been configured with templates.

b) Groovy Scripts

We have seen in the previous sections that we could use Groovy scripts to:

      • Process some business logic when an Action is activated from the ECM system. That was for example the case when we wanted to transform the binary DOC document into some text files.
      • Fill the select fields of a dialog template with dynamic data such as we did with calendar categories.

Here too the Groovy scripts are editable online because stored directly in the JCR.

To make this possible we had to modify the class loading mechanism in Groovy in order to:

- Load the imported object from the JCR

- Invalidate the loaded cache object of the class loader when a script was modified online. The use of the JCR Observation API was very useful in that case.

Thanks to the help of the Groovy team and especially Guillaume Laforge, the project Manager, we were able to do so very quickly.

Here too, there exists a ScriptService that you can programmatically query.

public interface ScriptService {
public CmsScript getScript(String scriptName) throws Exception;
public String getScriptAsText(String scriptName) throws Exception;
public NodeIterator getScripts() throws Exception;
public boolean hasScripts() throws Exception;
public void addScript(String name, String text) throws Exception;
public void removeScript(String scriptName) throws Exception;

c) Rules

We already talked about our native Drools support in the first article. We have also allowed the ECM user to plug rules with ECM Actions in order to launch business rules when a document was added, removed or read.

Here too the rule DRL are modifiable online and there exist a Rules service that is quite similar to the script one.

d) Action Types

It is possible to view and add ActionType online. It is important to understand, at least for the admin, that an ActionType is a simple custom NodeType that extends the “exo:action” NodeType.

By default, we predefine some ActionTypes, some that will activate Groovy script, some that will activate Business Processes or Business Rules as show in the next screenshot.

According to the ActionType you want to create you will have to extend one of the default type to either activate a script, a rule or a business process. Each time you change the value of the action type to extend (in the first select field) th en the second form label and field will change accordingly. For example in the case of a exo:businessProcessAction parent type, the second form will allow you to select among all the deployed business processes.

The variable fields allow you to provide more information to the script, rule or business process. In the case of the publication workflow, the “validator” key is a variable used by the business process to tell the identity of the next actor in the process. Note that you only tell about the variable key and not the value of it. Indeed the value will only be entered when an action instance of that new type will be created thanks to the associated dialog template.

Note that once an ActionType is defined, you will have to create a DocumentType out of it, aka create the dialog and view templates. The dialog template will need to include the variable as fields.

The ActionType services works with plugins that you can easily add. Each plugin is responsible of a type of action; hence there are 3 by default. Each plugin configuration XML file can also load predefined action instances such as the publication or backup workflows as shown in the next XML code fragment (for the XML syntax refer to the first article).

<object type="org.exoplatform.services.cms.actions.ActionConfig">
<field name="workspace"><string>production</string></field>
<field name="actions">
<collection type="java.util.ArrayList">
<object type="org.exoplatform.services.cms.actions.ActionConfig$Action">
<field name="type"><string>exo:workflowAction</string></field>
<field name="name"><string>publication</string></field>
<field name="description"><string>publication workflow</string></field>
<field name="srcWorkspace"><string>draft</string></field>
<field name="srcPath"><string>/cms/publications</string></field>
<field name="lifecyclePhase"><string>add</string></field>
<field name="roles"><string>*:/user</string></field>
<field name="variables">
<field name="mixins">
<collection type="java.util.ArrayList">
<object type="org.exoplatform.services.cms.actions.ActionConfig$Mixin">
<field name="name"><string>exo:move</string></field>
<field name="properties">

That XML will register a BPActionPlugin into the ActionServiceContainer . The BPActionPlugin holds an instance of type exo:businessPro cessAction named “publication” with all the associated properties.

The next two sections will introduce new products we are working on and that should be ready during the first two quarters of 2006. A lot of work has already be en done and you can already test and even use some parts of them in production as we do on our web site.

  • Research and development

This last section will introduce some of our current work for future products. The idea is to show how we leverage the existing platform and implemented standards to build a comprehensive and integrated set of cross cutting tools on which specialized products can be built.

A) Groupware

The groupware product is composed of several tools. Some were created in the first version of the platform such as the forum, the webmail or the wiki. And some are newly developed such as the shared calendar and the project manager.

The main goal behind that new product line is to make those different communications services leverage the JCR and ECM functionalities. Indeed, it makes a lot sense to store, structure and process content such as forum threads, calendar events, project tasks or emails thanks to the previously described ECM product. The next screenshot shows our forum portlet (currently based on a raw Database backend).

Therefore, in one hand we have to upgrade the existing tools that, like the forum, were directly based on relational databases; and in the other hand we have to deploy new products that were built directly with the JCR in mind.

In that section we will describe some features of the shared calendar, how we use JCR NodeTypes to structure calendar events following the iCal protocol structure, how the events form and views are rendered thanks to the dialog and view templates.

  • Calendar event structure

As stated before the calendar event is structured as a JCR NodeType that contains several properties but no sub node. As you can see those properties are similar to the one defined in the iCal protocol.

- exo:summary : subject of event

- exo:description : short description

- exo:comment : notes or comments

- exo:location : where the event takes place

- exo:dtstart : date/time start

- exo:dtend : date/time end

- exo:category : category (list of categories in ical)

- exo:fbtype : free/busy type

- exo:sharetype : share type (private / detail / freebusy)

The category property is chosen among a list of categories defined by the ECM admin, it can be “meeting”, “lunch”…

  • Calendar templates

As usual once we have a JCR NodeType, we need to assign the dialog and view templates that will allow creating the node instance (thanks to a node) or viewing it.

Every Groupware application will leverage that mechanism to provide an integrated and powerful framework to structure, store and manage several content types.

B) Business Intelligence Platform

The Business Intelligence product is probably the most unexpected one from us but it is also one of the most promising. It relies on the ObjectWeb project SpagoBI and will end in a deeply integrated product with our ECM one.

BI has been introduced to provide, thanks to techniques and tools, analytical reports and dashboard to decision makers. By default we will analyze our own portal data but it is possible to provide the same type of analysis for many different type of information usually more business logic oriented.

Among those tools we can find static or parametric reports, dashboards, data mining or multidimensional navigation ones (OLAP) that allow providing different views of the same data model, i.e. the Data Mart (subset of a Data Warehouse) as shown in the next screenshot.

So far, the SpagoBI project uses the eXo Platform portal in its first version to deploy a set of powerful portlets to render several reports and dashboards as well as a collaborative administration part in order to develop, test and publish BI objects.

In that first version, the integration goes up to the group’s management as the SpagoBi leverages our OrganizationService and the community concept to provide a collaborative and compliant BI portal.

We are currently working on a deeper integration with the SpagoBI team in order to provide:

  • A powerful Data Mart for the portal data. Hence, it will be – for example - possible to navigate through the OLAP cubes to get the all the portlets that a user saw during one portal session. Those monitoring tools will come to enhance the existing JMX default ones and will nicely complete them.
  • A powerful BI Objects structure thanks to JCR NodeTypes as well as an integrated ECM Workflow for moving the objects from one workspace to the other as described in the previous ECM section.

Creating the Data Mart model is the most important part of the BI job. Indeed, once we have that model, building on top of it all the BI tools such as reports, OLAP, etc is quite simple.

A Data Mart is a kind of normalized relational database that logs the Facts in one table, i.e. the value that we are interested in, as well as the Dimension in other tables. The dimensions items reference the fact table.

Therefore, the challenge is to first model what you would like to monitor and then fill the Data Mart model with the real data either in real or batch time. That last operation can be done thanks to ETL tools that will extract information from many different data sources to load them in the Data Mart tables. It can also be done directly as this is the case for the portal data.

We will write a dedicated article soon to describe in details all these steps.

This ends that two-part article which describes what are the new products that compose the eXo Platform v2 product line. If you have any questions you can ask them on our web site forum.

Have a nice year 2006.

Special thanks to Grazia Cazzin and Antonia Majori from the SpagoBI fame.

Capture: we provide several ways to submit structured or unstructured content ( Microsoft Office documents) into the repository. It is indeed possible to import

Dig Deeper on Modular containers

Start the conversation

Send me notifications when other members comment.

Please create a username to comment.