All eXo services are built around the eXo kernel, or the service management layer, which manages the configuration and the execution of all components. The main kernel object is the eXo Container, a micro-container that glues services together through dependency injection. The container is responsible for loading services/components.

This chapter will introduce the concepts of Container and Services, and will give you an overview before configuring basic services.

A container is always required to access a service, because the eXo kernel relies on dependency injection. This means that the life cycle of a service (for example, instantiating, opening and closing streams, disposing) is handled by a dependency provider, such as the eXo Container, rather than the consumer. The consumer only needs a reference to an implementation of the requested service. The implementation is configured in an .xml configuration file that comes with every service. To learn more about dependency injection, visit here.

eXo has two types of container: RootContainer and PortalContainer.

The RootContainer holds the low level components. It is automatically started before the PortalContainer. You will rarely interact directly with the RootContainer except when you activate your own extension. The PortalContainer is created for each portal (one or several portals). All services started by this container will run as embedded in the portal. It also gives access to components of its parent RootContainer.

In your code, if you need to invoke a service of a container, you can use the ExoContainerContext helper from any location. The code below shows you a utility method that you can use to invoke any eXo service.


public class ExoUtils {

  /**
   * Get a service from the portal container
   * @param type : component type
   * @return the concrete instance retrieved in the container using the type as key
   */
  public <T>T getService(Class<T> type) {
    return (T)ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(type);
  }
  
}

Then, invoking becomes as easy as:

  OrganizationService orgService = ExoUtils.getService(OrganizationService.class)

To declare a service, you must add an .xml configuration file to a specific place. This file can be in the jar file, in a webapp or in the external configuration directory. If you write a new component for the eXo Container, you should always provide a default configuration in your jar file. This default configuration must be in the file /conf/portal/configuration.xml in your jar.

A configuration file can specify several services, so there can be several services in one jar file.

You can provide initial parameters for your service by defining them in the configuration file. The followings are different parameters:

For the object-param component, you can look at the LDAP service:

An object-param is used to create an object (which is actually a Java Bean) passed as a parameter to the service. This object-param is defined by a name, a description and exactly one object. The object tag defines the type of the object, while the field tags define parameters for that object.

You can see how the service accesses the object in the code below:

The passed object is LDAPConnectionConfig, which is a classic Java Bean. It contains all fields defined in the configuration files and also the appropriate getters and setters (not listed here). You also can provide default values. The container creates a new instance of your Java Bean and calls all setters whose values are configured in the configuration file.

GateIn extensions are special .war files that are recognized by eXo Platform and contribute to custom configurations to the PortalContainer. To create your own portal, you will have to create a GateIn extension.

The extension mechanism makes possible to extend or even override portal resources in almost plug-and-play way. You simply add a .war archive with your custom resources to the war folder and edit the configuration of the PortalContainerConfig service. Customizing a portal does not involve unpacking and repacking the original portal .war archives. Instead, you need to create your own .war archive with your own configurations, and modify resources. The content of your custom .war archive overrides the resources in the original archives.

The most elegant way to reuse configuration for different coexisting portals is by way of extension mechanism - by inheriting resources and configuration from existing web archives, and just adding extra resources to it, and overriding those that need to be changed by including modified copies.

If you ship servlets or servlet filters as part of your portal extension, and if you need to access specific resources of portal at any time during processing of the servlet or filter request, you need to make sure the servlet/filter is associated with the current container. The proper way to do that is to make your servlet extend org.exoplatform.container.web.AbstractHttpServlet class. This will not only properly initialize the current PortalContainer for you, but also set the current thread's context classloader to one that looks for resources in associated web applications in the order specified by Dependencies configuration (as explained in the Extension mechanism section).

Similarly for filters, make sure your filter class extends org.exoplatform.container.web.AbstractFilter. Both AbstractHttpServlet and AbstractFilter have the method getContainer(), which returns the current PortalContainer.

The webapps are loaded in the order defined in the list of dependencies of the PortalContainerDefinition. You then need to deploy the starter.war; otherwise, the webapps will be loaded in the default application server's order', such as the loading order of the Application Server.

If you need to customize your portal by adding a new extension and/or a new portal, you need to define the related PortalContainerDefinitions and to deploy the starter. Otherwise, you do not need to define any PortalContainerDefinition or deploy the starter.

First, you need to tell eXo Platform to load WEB-INF/conf/configuration.xml of your extension, you need to declare it as a PortalContainerConfigOwner. Next, open the file WEB-INF/web.xml of your extension and add a listener:

You need to register your extension in the portal container. This is done by the .xml configuration file like this:

We define a PortalContainerDefinitionChangePlugin plugin to the PortalContainerConfig. The plugin declares a list of dependencies that are webapps. The apply.default=true indicates that your extension is actually extending portal.war. You need to package your extension into a .war file and put it to the tomcat webapps folder, then restart the server.

In your portal, if you want to add your own property file to support localization for your keys, you can do as follows:

All data in eXo Platform is stored in a Java Content Repository (JCR). JCR is a Java specification (JSR-170 ) for a type of Object Database tailored to the storage, searching, and retrieval of hierarchical data. It is useful to content management systems, which require storage of objects associated with metadata. A JCR also provides versioning, transactions, observations of changes in data, and import or export of data in XML. The data in JCR is stored hierarchically in a tree of nodes with associated properties.

Also, the JCR is primarily used as an internal storage engine. Accordingly, eXo Content lets you manipulate JCR data directly in several places.

A content repository consists of one or more workspaces. Each workspace contains a tree of items.

To access a repository's content from a service:

You can use the session object to retrieve your node content.

A javax.jcr.Repository object can be obtained via one of the following ways:

Next, you need to log in the server to get a Session object by either of two ways:

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

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

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

This way is only applied when you run an implementation of eXo Platform embedded in the portal.

In embedded cases, the implementation will directly leverage the organization and security services that rely on LDAP or DB storage and JAAS login modules. Single-Sign-On products can now also be used as eXo Platform v.2 which supports them.

JCR Session common considerations