Appendix A. The eXo Kernel

A.1. The eXo Kernel

The Red Hat JBoss Portal is built as a set of services on top of a dependency injection kernel. The kernel provides configuration, life-cycle handling, component scopes and some core services.
The portal kernel and the JCR used in the portal use the Inversion of Control (IoC) system to control service instantiation. This method is also known as 'dependency injection'.
In this system, services are not responsible for the instantiation of the components on which they depend. It prevents objects creating the instances of any objects referenced. This task is delegated to the container, as described in Figure A.1, “Inversion of Control”:
Diagram explaining how Inversion of Control works, and how the Assembler plays a key role in controlling dependency injection.

Figure A.1. Inversion of Control

There are two ways to inject a dependency :
Using a constructor:
public ServiceA(ServiceB serviceB)
Using setter methods:
public void setServiceB(ServiceB serviceB)
When a client service can not be stored in the container then the service locator pattern is used:
public ServiceA(){
this.serviceB =Container.getSInstance().getService(ServiceB.class);
}
The container package is responsible for building a hierarchy of containers. Each service is registered in a container according to the XML configuration file it is defined in. There can be several PortalContainer instances that all are children of the RootContainer.
The behavior of the hierarchy is similar to class loader behavior. When a portal application is integrated with eXo services, these services are looked up through the PortalContainer.. If the service cannot be found, then the class loader looks in the parent container. This means the reusable business logic components can be loaded in the same container (here the RootContainer) and differentiates the service implementation from one portal instance to the other by loading different service implementations in two sibling PortalContainers.
If the Portal Container is thought of as a service repository for all the business logic in a portal instance, it is easier to understand why several PortalContainers allows several portals to be managed (each one deployed as a single war) in the same server by changing XML configuration files.
The default configuration XML files are packaged in the service Java Archive (JAR). There are three configuration.xml files: one for each container type. This file defines the list of services and their init parameters that are loaded in the corresponding container.
Service components exist in two scopes:
  • RootContainer, which is a base container and contains services that exist independently of any portal. The RootContainer can be accessed by all portals. This container plays an important role during startup, but must not be used directly.
  • PortalContainer, in which each portal exists. This scope contains services that are common for a set of portals, and services which must remain unique to each portal instance. This service component is created when a portal web application (in the init() method of the PortalController servlet) starts.
Diagram with Application Server, Root Container, and two Portal Container layers. Portal Container one has Portal A, Portal B, and Portal C declared. Portal Container Two has Portal D declared.

Figure A.2. Portal Containers

Because several portal container instances can exist for each JVM, configuring loaded services for each instance is an important feature. All the default configuration files located in the service impl JAR can be overridden from the portal.war.
Whenever a specific service is looked up through the PortalContainer, and the service is not available, the lookup is delegated further up to the RootContainer.
The portal can have default instances of a certain component in the RootContainer, and portal specific instances in some or all PortalContainers, that override the default instance.
Whenever a portal application has to be integrated more closely with eXo services, these services can be looked up through the PortalContainer.

Important

Only officially documented services should be accessed this way, and used according to their supporting documentation. Most services are an implementation detail of eXo, and subject to change without notice.

A.2. Kernel Configuration Namespace

To be effective, the namespace URI http://www.exoplatform.org/xml/ns/kernel_1_2.xsd must be the target namespace of the XML configuration file.
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
           xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">


...
</configuration>
The eXo Kernel will resolve variables declared in configuration files. For example, the following configuration would be interpreted correctly:
<configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">

<import>${db.configuration.path}/db.xml</import>
<import>${java.io.tmpdir}/bindfile.xml</import>
<import>simple.xml</import>

</configuration>
Supported variables include System properties, and variables specific to the portal container. Variables are described in the proceeding sections.

A.3. Configuration Retrieval

The container performs the following steps for configuration retrieval, depending on the container type.
This container is used by non-portal applications, and configurations are overloaded in the following lookup sequence:
  1. Services default RootContainer configurations from JAR files /conf/configuration.xml.
  2. Services default PortalContainer configurations from JAR files /conf/portal/configuration.xml.
  3. Web applications configurations from WAR files /WEB-INF/conf/configuration.xml
  4. Configuration URL for PortalContainer, based on the following caveats:
    • If the configuration URL was initialized to be added to services defaults using PortalContainer.addConfigurationURL(containerConf); the configuration from the containerConf overrides services configured in the file only.
    • The $JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/configuration.xml is the only path that states the correct location for the configuration.
The search looks for a configuration file in each JAR/WAR available from the classpath using the current thread context classloader. During the search these configurations are added to a set.
If the service was configured previously and the current JAR contains a new configuration of that service, the latest (from the current JAR/WAR) will replace the previous one. The last one will be applied to the service during the services start phase.

Warning

No dependencies between JAR files contained in /conf/portal/configuration.xml and /conf/configuration.xml are loaded because there is no way of determining the JAR loading order prior to start.
To overload configuration information located in these files of a JAR file, load from another configuration file that is loaded after configurations from JAR files (for example, /conf/portal/configuration.xml in the portal itself).
After all configuration available in the system is processed, the container will initialize and start each service in order of the dependency injection (DI).

Important

Be careful when configuring the same service in different configuration files.
To ensure service configuration is loaded as expected, configure a service within its own JAR.
In the case of a portal configuration, strictly reconfigure the services in portal WAR files, or from an external configuration file.
There are services that are configured more than once, depending on the business logic of the service. A service may initialize the same resource (shared with other services), or may add a particular object to a set of objects (also shared with other services). For services that initialize the same resource, it is critical to determine which service configuration will be used (the last one to be loaded). For services that add objects to a set of objects, the initialization order is not important providing the parameter objects are independent.
In case of problems with service configuration, it is important to know from which JAR/WAR the configuration originates. The JVM system property org.exoplatform.container.configuration.debug can be used to identify this information.
java -Dorg.exoplatform.container.configuration.debug ...
If the property is enabled, the container configuration manager logs the configuration adding process at INFO level.
The effective configuration of the StandaloneContainer, RootContainer and/or PortalContainer can be shown using the getConfigurationXML() method that is exposed through JMX at the container level. This method exposes the effective configuration, in XML format, that the kernel interpreted. This information could be helpful when analyzing how a given component or plug-in has been initialized.

A.4. PortalContainer Advanced Concepts

Since eXo JCR 1.12, a new set of features are available that extend portal applications.

A.4.1. Add new configuration files from a WAR file

A ServletContextListener called org.exoplatform.container.web.PortalContainerConfigOwner notifies the application that a web application provides some configuration to the portal container, and this configuration file is the file WEB-INF/conf/configuration.xml available in the web application itself.
If the WAR file contains configuration to add to the PortalContainer add the following lines to the web.xml file.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
                 "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
...
  <!-- ================================================================== -->
  <!--           LISTENER                                                 -->
  <!-- ================================================================== -->
  <listener>
    <listener-class>org.exoplatform.container.web.PortalContainerConfigOwner</listener-class>
  </listener>
...
</web-app>

A.4.2. Creating PortalContainers from a WAR File

Important

In Red Hat JBoss Portal, the PortalContainerCreator is already managed by the file starter.war/ear.
A ServletContextListener called org.exoplatform.container.web.PortalContainerCreator creates the current portal containers that have been registered. It is assumed that the web applications have already been loaded before calling PortalContainerCreator.contextInitialized.

A.4.3. Defining a PortalContainer with its dependencies and its settings

The PortalContainerDefinition contains the name of the portal container, the name of the rest context, the name of the realm, the web application dependencies ordered by loading priority, and the settings.

Example A.1. Defining a PortalContainerDefinition

Define a PortalContainerConfig at the RootContainer level to define a PortalContainerDefinition.
  <component>
    <!-- The full qualified name of the PortalContainerConfig -->
    <type>org.exoplatform.container.definition.PortalContainerConfig</type>
    <init-params>
      <!-- The name of the default portal container -->
      <value-param>
        <name>default.portal.container</name>
        <value>myPortal</value>
      </value-param>
      <!-- The name of the default rest ServletContext -->
      <value-param>
        <name>default.rest.context</name>
        <value>myRest</value>
      </value-param>
      <!-- The name of the default realm -->
      <value-param>
        <name>default.realm.name</name>
        <value>my-exo-domain</value>
      </value-param>
     <!-- Indicates whether the unregistered webapps have to be ignored -->
     <value-param>
        <name>ignore.unregistered.webapp</name>
        <value>true</value>
     </value-param>
      <!-- The default portal container definition -->
      <!-- It cans be used to avoid duplicating configuration -->
      <object-param>
        <name>default.portal.definition</name>
        <object type="org.exoplatform.container.definition.PortalContainerDefinition">
          <!-- All the dependencies of the portal container ordered by loading priority -->
          <field name="dependencies">
            <collection type="java.util.ArrayList">
              <value>
                <string>foo</string>
              </value>
              <value>
                <string>foo2</string>
              </value>
              <value>
                <string>foo3</string>
              </value>
            </collection>
          </field>        
          <!-- A map of settings tied to the default portal container -->
          <field name="settings">
            <map type="java.util.HashMap">
              <entry>
                <key>
                  <string>foo5</string>
                </key>
                <value>
                  <string>value</string>
                </value>
              </entry>
              <entry>
                <key>
                  <string>string</string>
                </key>
                <value>
                  <string>value0</string>
                </value>
              </entry>
              <entry>
                <key>
                  <string>int</string>
                </key>
                <value>
                  <int>100</int>
                </value>
              </entry>
            </map>
          </field>
          <!-- The path to the external properties file -->
          <field name="externalSettingsPath">
            <string>classpath:/org/exoplatform/container/definition/default-settings.properties</string>
          </field>
        </object>
      </object-param>
    </init-params>
  </component>

PortalContainerConfig Parameters

Note

Parameter values marked with a (*) can be defined through System properties like any values in configuration files, and variables loaded by the PropertyConfigurator. For example, in the portal, it would be all the variables defined in the file configuration.properties by default.
default.portal.container (*)
The name of the default portal container. This field is optional.
default.rest.context (*)
The name of the default rest ServletContext. This field is optional.
default.realm.name (*)
The name of the default realm. This field is optional.
ignore.unregistered.webapp (*)
Indicates whether the unregistered webapps have to be ignored.
This field is optional and is set to false by default.
If a webapp has not been registered as a dependency of any portal container, the application will use the value of this parameter to determine how to classify the webapp:
  • If set to false, the webapp will be considered by default as a dependency of all the portal containers.
  • If set to true, the webapp will not be considered by default as a dependency of any portal container, and is ignored.
default.portal.definition
The definition of the default portal container. This field is optional. The expected type is org.exoplatform.container.definition.PortalContainerDefinition that is described below. Allow the parameters defined in this default PortalContainerDefinition will be the default values.

Example A.2. Defining a PortalContainerDefinition at the RootContainer Level Using a Plug-in

A new PortalContainerDefinition can be defined at the RootContainer level using an external plug-in:
  <external-component-plugins>
    <!-- The full qualified name of the PortalContainerConfig -->
    <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>
    <component-plugin>
      <!-- The name of the plugin -->
      <name>Add PortalContainer Definitions</name>
      <!-- The name of the method to call on the PortalContainerConfig in order to register the PortalContainerDefinitions -->
      <set-method>registerPlugin</set-method>
      <!-- The full qualified name of the PortalContainerDefinitionPlugin -->
      <type>org.exoplatform.container.definition.PortalContainerDefinitionPlugin</type>
      <init-params>
        <object-param>
          <name>portal</name>
          <object type="org.exoplatform.container.definition.PortalContainerDefinition">
            <!-- The name of the portal container -->
            <field name="name">
              <string>myPortal</string>
            </field>
            <!-- The name of the context name of the rest web application -->
            <field name="restContextName">
              <string>myRest</string>
            </field>
            <!-- The name of the realm -->
            <field name="realmName">
              <string>my-domain</string>
            </field>
            <!-- All the dependencies of the portal container ordered by loading priority -->
            <field name="dependencies">
              <collection type="java.util.ArrayList">
                <value>
                  <string>foo</string>
                </value>
                <value>
                  <string>foo2</string>
                </value>
                <value>
                  <string>foo3</string>
                </value>
              </collection>
            </field>
            <!-- A map of settings tied to the portal container -->
            <field name="settings">
              <map type="java.util.HashMap">
                <entry>
                  <key>
                    <string>foo</string>
                  </key>
                  <value>
                    <string>value</string>
                  </value>
                </entry>
                <entry>
                  <key>
                    <string>int</string>
                  </key>
                  <value>
                    <int>10</int>
                  </value>
                </entry>
                <entry>
                  <key>
                    <string>long</string>
                  </key>
                  <value>
                    <long>10</long>
                  </value>
                </entry>
                <entry>
                  <key>
                    <string>double</string>
                  </key>
                  <value>
                    <double>10</double>
                  </value>
                </entry>
                <entry>
                  <key>
                    <string>boolean</string>
                  </key>
                  <value>
                    <boolean>true</boolean>
                  </value>
                </entry>                                
              </map>
            </field>            
            <!-- The path to the external properties file -->
            <field name="externalSettingsPath">
              <string>classpath:/org/exoplatform/container/definition/settings.properties</string>
            </field>
          </object>
        </object-param>
      </init-params>
    </component-plugin>
  </external-component-plugins>

PortalContainerDefinition Parameter Values

name (*)
The name of the portal container. This field is mandatory .
restContextName (*)
The name of the context name of the rest web application. This field is optional. The default value will be defined at the PortalContainerConfig level.
realmName (*)
The name of the realm. This field is optional. The default value will be defined at the PortalContainerConfig level.
dependencies
All the dependencies of the portal container ordered by loading priority. This field is optional. The default value will be defined at the PortalContainerConfig level.
The dependencies are in fact the list of the context names of the web applications from which the portal container depends on. The dependency order is crucial because it will be interpreted the same way by several components of the platform. All components will consider the first element in the list less important than the second element and so on.
Dependency order is used to define the following:
  • Know the loading order of all the dependencies.
  • If several PortalContainerConfigOwner dependencies exist, the unified ServletContext (PortalContainer.getPortalContext()) is called to get a resource. It will attempt to get the resource in the ServletContext of the most important PortalContainerConfigOwner (the last in the dependency list). If it is able to find the resource, it will try again with the second most important PortalContainerConfigOwner and so on.
settings
A java.util.Map of internal parameters to apply to the portal container. Parameters could have any type of value. This field is optional. If some internal settings are defined at the PortalContainerConfig level, the two settings maps are merged. If a setting with the same name is defined in both maps, it will keep the value defined at the PortalContainerDefinition level.
externalSettingsPath
The path of the external properties file to load as default settings to the portal container. This field is optional. If some external settings are defined at the PortalContainerConfig level, the two settings maps are merged. If a setting with the same name is defined in both maps, it will keep the value defined at the PortalContainerDefinition level. The external properties files can be either of type "properties" or of type "xml". The path will be interpreted as follows:
  1. If the path doesn't contain any prefix of type "classpath:", "jar:" or "file:", it is assumed the file could be externalized. The following rules are applied:
    1. If a file exists at ${exo-conf-dir}/portal/${portalContainerName}/${externalSettingsPath} this file is loaded.
    2. If no file exists, it is assumed that the path can be interpreted by the ConfigurationManager.
  2. If the path contains a prefix, it is assumed that the path can be interpreted by the ConfigurationManager.
When a PortalContainerDefinition is used to define the default portal container, some extra logic is used in the fields.

PortalContianerDefinition Parameter Descriptions When Used for The Default Portal Container

Note

Parameter values marked with an asterix (*) can be defined through System properties like any values in configuration files, and variables loaded by the PropertyConfigurator. For example, in the portal it would be all the variables defined in the file configuration.properties by default.
name (*)
The name of the portal container. This field is optional. The default portal name is determined by the following logic:
  1. If this field is not empty, the default value is the value of this field.
  2. If this field is empty and the value of the parameter default.portal.container is not empty, the default value will be the value of the parameter.
  3. If this field and the parameter default.portal.container are both empty, the default value is "portal".
restContextName (*)
The name of the context name of the rest web application. This field is optional. The default value is determined by the following logic:
  1. If this field is not empty, then the default value will be the value of this field.
  2. If this field is empty and the value of the parameter default.rest.context is not empty, then the default value will be the value of the parameter.
  3. If this field and the parameter default.rest.context are both empty, the default value will be "rest".
realmName (*)
The name of the realm. This field is optional. The default value is determined by the following logic:
  1. If this field is not empty, then the default value is the value of this field.
  2. If this field is empty and the value of the parameter default.realm.name is not empty, then the default value is the value of the parameter.
  3. If this field and the parameter default.realm.name are both empty, the default value is "exo-domain".
dependencies
All dependencies of the portal container ordered by loading priority. This field is optional. If this field has a non empty value, it is interpreted as the default list of dependencies.
settings
A java.util.Map of internal parameters to associate with the default portal container. Parameters can be of any data type. This field is optional.
externalSettingsPath
The path of the external properties file to load as default settings to the default portal container. This field is optional. The external properties files can be either of type "properties" or of type "xml". The path is interpreted as follows:
  1. If the path does not contain any prefix of type "classpath:", "jar:" or "file:", it is assumed that the file could be externalized. The following rule subset is applied:
    1. If a file exists at ${exo-conf-dir}/portal/${externalSettingsPath}, the file is loaded.
    2. If no file exists at the previous path, it is assumed that the path can be interpreted by the ConfigurationManager.
  2. If the path contains a prefix, it is assumed that the path can be interpreted by the ConfigurationManager.
Internal and external settings are both optional, however the application will merge the settings if a non empty value is provided. If the same setting name exists in both settings, the following rules apply:
  1. If the value of the external setting is null, the value is ignored.
  2. If the value of the external setting is not null, and the value of the internal setting is null, the final value is the external setting value that is of type String.
  3. If both values are not null, the external setting value is converted into the target type (the internal setting value) through the static method valueOf(String). The following rule subset is applied:
    1. If the method cannot be found, the final value is the external setting value that is of type String.
    2. If the method can be found and the external setting value is an empty String, the external setting value is ignored.
    3. If the method can be found and the external setting value is not an empty String but the method call fails, the external setting value is ignored.
    4. If the method can be found, the external setting value is not an empty String, and the method call succeeds, the final value is the external setting value that is the same type as the internal setting value.

A.4.4. PortalContainer Settings

The portal.container.* variable permits value injection into portal container configuration files. For example, to get the value of a setting called "name", use ${portal.container.name}. The following internal variables are also valid:

PortalContainer Internal Variables

portal.container.name
Gives the name of the current portal container.
portal.container.rest
Gives the context name of the rest web application of the current portal container.
portal.container.realm
Gives the realm name of the current portal container.

Example A.3. portal.container.* Usage Example

<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
  xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">
  <component>
    <type>org.exoplatform.container.TestPortalContainer$MyComponent</type>
    <init-params>
      <!-- The name of the portal container -->
      <value-param>
        <name>portal</name>
        <value>${portal.container.name}</value>
      </value-param>
      <!-- The name of the rest ServletContext -->
      <value-param>
        <name>rest</name>
        <value>${portal.container.rest}</value>
      </value-param>
      <!-- The name of the realm -->
      <value-param>
        <name>realm</name>
        <value>${portal.container.realm}</value>
      </value-param>
      <value-param>
        <name>foo</name>
        <value>${portal.container.foo}</value>
      </value-param>
      <value-param>
        <name>before foo after</name>
        <value>before ${portal.container.foo} after</value>
      </value-param>
    </init-params>
  </component>
</configuration>

Example A.4. Create a New Variable from Existing Variables

In the properties file corresponding to the external settings, variables previously defined in the internal or external settings can be reused to create a new variable. Contrary to Example A.3, “portal.container.* Usage Example” the prefix portal.container. is not needed.
my-var1=value 1
my-var2=value 2
complex-value=${my-var1}-${my-var2}

Example A.5. Settings Created Using System Parameters

External and internal settings can also be created based on the values of system parameters. The System parameters can be defined at launch time, or by using the PropertyConfigurator.
temp-dir=${java.io.tmpdir}${file.separator}my-temp

Note

System parameters of type java.lang.String can only be used when generating new internal setting variables.

Example A.6. Specify a Dynamically-changing Variable

A generic variable can be defined in the settings of the default portal container. The value of this variable will change dynamically, according to the current portal container.
my-generic-var=value of the portal container "${name}"
If this variable is defined at the default portal container level, the value of this variable for a portal container called "sales" is value of the portal container "sales".

A.4.5. Dynamically Changing a PortalContainerDefinition

It is possible to use component-plugin elements to dynamically change a PortalContainerDefinition.

Example A.7. 

The dependency sales is added to the default portal container, and to the portal containers named shop1 and shop2:
<external-component-plugins>
  <!-- The full qualified name of the PortalContainerConfig -->
  <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>
  <component-plugin>
    <!-- The name of the plugin -->
    <name>Change PortalContainer Definitions</name>
    <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions -->
    <set-method>registerChangePlugin</set-method>
    <!-- The full qualified name of the PortalContainerDefinitionChangePlugin -->
    <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type>
    <init-params>
      <value-param>
        <name>apply.default</name>
        <value>true</value>
      </value-param>
      <values-param>
        <name>apply.specific</name>
        <value>shop1</value>
        <value>shop2</value>
      </values-param>  
      <object-param>
        <name>change</name>
        <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependencies">
          <!-- The list of name of the dependencies to add -->
          <field name="dependencies">
            <collection type="java.util.ArrayList">
              <value>
                <string>foo</string>
              </value>
            </collection>
          </field>
        </object>
      </object-param>     
    </init-params>
  </component-plugin>
</external-component-plugins>

PortalContainerDefinitionChangePlugin Parameters

Note

Parameter values marked with a (*) can be defined through System properties like any values in configuration files, and variables loaded by the PropertyConfigurator. In the portal, an example of acceptable values would be all variables defined in the file configuration.properties by default.
apply.all (*)
Indicates whether the changes have to be applied to all the portal containers or not. The default value of this field is false. This field is a ValueParam and is not mandatory.
apply.default (*)
Indicates whether the changes have to be applied to the default portal container or not. The default value of this field is false. This field is a ValueParam and is not mandatory.
apply.specific (*)
A set of specific portal container names to apply the changes to. This field is a ValuesParam and is not mandatory.

Other Expected Parameters

The rest of the expected parameters are ObjectParam of type PortalContainerDefinitionChange. Those parameters are in fact the list of changes to apply to one or several portal containers. If the list of changes is empty, the component plug-in is ignored. The supported implementations of PortalContainerDefinitionChange are described later in this section.
The following algorithm is used to identify how changes are applied to portal containers:
  1. If the parameter apply.all is set to true the corresponding changes are applied to all the portal containers and other parameters will be ignored.
  2. If the parameter apply.default is set to true and the parameter apply.specific is null,the corresponding changes are applied to the default portal container only.
    If apply.specific is not null, the corresponding changes are applied to the default portal container, and the list of specific portal containers.
  3. If the parameter apply.default is set to false or has not been set, and the parameter apply.specific is null, the corresponding changes are applied to the default portal container only.
    If apply.specific is not null, the corresponding changes are applied to the list of specific portal containers.

A.4.5.1. PortalContainerDefinitionChange Implementations

The modifications that can be applied to a PortalContainerDefinition must be a class of type PortalContainerDefinitionChange. The product ships implementations described in the following sections.
A.4.5.1.1. AddDependencies
This modification adds a list of dependencies at the end of the list of dependencies defined into the PortalContainerDefinition. The full qualified name is org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependencies.

AddDependencies Parameters

dependencies
A String list, corresponding to the list of dependency names to add. If the field is unpopulated, the change is ignored.

Example A.8. Appending a Dependency

This example adds foo at the end of the dependency list of the default portal container.
<external-component-plugins>
  <!-- The full qualified name of the PortalContainerConfig -->
  <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>
  <component-plugin>
    <!-- The name of the plugin -->
    <name>Change PortalContainer Definitions</name>
    <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions -->
    <set-method>registerChangePlugin</set-method>
    <!-- The full qualified name of the PortalContainerDefinitionChangePlugin -->
    <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type>
    <init-params>
      <value-param>
        <name>apply.default</name>
        <value>true</value>
      </value-param>
      <object-param>
        <name>change</name>
        <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependencies">
          <!-- The list of name of the dependencies to add -->
          <field name="dependencies">
            <collection type="java.util.ArrayList">
              <value>
                <string>foo</string>
              </value>
            </collection>
          </field>
        </object>
      </object-param>     
    </init-params>
  </component-plugin>
</external-component-plugins>
A.4.5.1.2. AddDependenciesBefore
This modification adds a list of dependencies before a given target dependency defined into the list of dependencies of the PortalContainerDefinition. The fullly qualified name is org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependenciesBefore.

AddDependenciesBefore Parameters

dependencies
A String list, corresponding to the list of dependency names to add. If the field is unpopulated, the change is ignored.
target
The name of the dependency that the new dependencies are added before. New dependencies are added in first position to the list if this field is null, or the target dependency cannot be found in the list of dependencies defined into the PortalContainerDefinition.

Example A.9. Adding Multiple Dependencies

This example adds dependency1 before dependency2 in the dependency list of the default portal container.
<external-component-plugins>
  <!-- The full qualified name of the PortalContainerConfig -->
  <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>
  <component-plugin>
    <!-- The name of the plugin -->
    <name>Change PortalContainer Definitions</name>
    <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions -->
    <set-method>registerChangePlugin</set-method>
    <!-- The full qualified name of the PortalContainerDefinitionChangePlugin -->
    <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type>
    <init-params>
      <value-param>
        <name>apply.default</name>
        <value>true</value>
      </value-param>
      <object-param>
        <name>change</name>
        <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependenciesBefore">
          <!-- The list of name of the dependencies to add -->
          <field name="dependencies">
            <collection type="java.util.ArrayList">
              <value>
                <string>dependency1</string>
              </value>
            </collection>
          </field>
          <!-- The name of the target dependency -->
          <field name="target">
            <string>dependency2</string>
          </field>
        </object>
      </object-param>     
    </init-params>
  </component-plugin>
</external-component-plugins>
A.4.5.1.3. AddDependenciesAfter
This modification adds a list of dependencies before a given target dependency defined into the list of dependencies of the PortalContainerDefinition. The full qualified name is org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependenciesAfter.

AddDependenciesAfter Parameters

dependencies
A list of String corresponding to the list of dependency names to add. If the field is unpopulated, the change is ignored.
target
The name of the dependency that the new dependencies are added before. New dependencies are added in first position to the list if this field is null, or the target dependency cannot be found in the list of dependencies defined into the PortalContainerDefinition.

Example A.10. Adding Dependencies After

This example adds dependency1 after dependency2 in the dependency list of the default portal container.
<external-component-plugins>
  <!-- The full qualified name of the PortalContainerConfig -->
  <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>
  <component-plugin>
    <!-- The name of the plugin -->
    <name>Change PortalContainer Definitions</name>
    <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions -->
    <set-method>registerChangePlugin</set-method>
    <!-- The full qualified name of the PortalContainerDefinitionChangePlugin -->
    <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type>
    <init-params>
      <value-param>
        <name>apply.default</name>
        <value>true</value>
      </value-param>
      <object-param>
        <name>change</name>
        <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddDependenciesAfter">
          <!-- The list of name of the dependencies to add -->
          <field name="dependencies">
            <collection type="java.util.ArrayList">
              <value>
                <string>dependency1</string>
              </value>
            </collection>
          </field>
          <!-- The name of the target dependency -->
          <field name="target">
            <string>dependency2</string>
          </field>
        </object>
      </object-param>     
    </init-params>
  </component-plugin>
</external-component-plugins>
A.4.5.1.4. AddSettings
This modification adds new settings to a PortalContainerDefinition. The full qualified name is org.exoplatform.container.definition.PortalContainerDefinitionChange$AddSettings.

AddSettings Parameters

settings
A map of <String, Object> corresponding to the settings to add. The change is ignored if the value of this field is empty.

Example A.11. Add Settings

This example adds the settings string and stringX to the settings of the default portal container.
<external-component-plugins>
  <!-- The full qualified name of the PortalContainerConfig -->
  <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>
  <component-plugin>
    <!-- The name of the plugin -->
    <name>Change PortalContainer Definitions</name>
    <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions -->
    <set-method>registerChangePlugin</set-method>
    <!-- The full qualified name of the PortalContainerDefinitionChangePlugin -->
    <type>org.exoplatform.container.definition.PortalContainerDefinitionChangePlugin</type>
    <init-params>
      <value-param>
        <name>apply.default</name>
        <value>true</value>
      </value-param>
      <object-param>
        <name>change</name>
        <object type="org.exoplatform.container.definition.PortalContainerDefinitionChange$AddSettings">
          <!-- The settings to add to the to the portal containers -->
          <field name="settings">
            <map type="java.util.HashMap">
              <entry>
                <key>
                  <string>string</string>
                </key>
                <value>
                  <string>value1</string>
                </value>
              </entry>
              <entry>
                <key>
                  <string>stringX</string>
                </key>
                <value>
                  <string>value1</string>
                </value>
              </entry>
            </map>
          </field>
        </object>
      </object-param>     
    </init-params>
  </component-plugin>
</external-component-plugins>

A.4.6. Dynamically Disable a Portal Container

It is possible to use component-plugin elements to dynamically disable one or more portal containers.

Example A.12. Disabling a Portal Container

The example shows how to disable the portal container named sales.
<external-component-plugins>
  <!-- The full qualified name of the PortalContainerConfig -->
  <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>
  <component-plugin>
    <!-- The name of the plugin -->
    <name>Disable a PortalContainer</name>
    <!-- The name of the method to call on the PortalContainerConfig in order to register the changes on the PortalContainerDefinitions -->
    <set-method>registerDisablePlugin</set-method>
    <!-- The full qualified name of the PortalContainerDefinitionDisablePlugin -->
    <type>org.exoplatform.container.definition.PortalContainerDefinitionDisablePlugin</type>
    <init-params>
      <!-- The list of the name of the portal containers to disable -->
      <values-param>
        <name>names</name>
        <value>sales</value>
      </values-param>
    </init-params>
  </component-plugin>
</external-component-plugins>

PortalContainerDefinitionDisablePlugin Parameters

names (*)
Specifies a list of portal container names to disable.

Note

Values of parameters marked with an (*) can be defined through System properties like any values in configuration files, and variables loaded by the PropertyConfigurator. In the portal, parameters would be all the variables defined in the file configuration.properties by default.
To prevent access to a disabled web application corresponding to PortalContainer, ensure the following HTTP Filter (or a sub class of it) has been added to the web.xml file, at the beginning of the file.
<filter>
  <filter-name>PortalContainerFilter</filter-name>
  <filter-class>org.exoplatform.container.web.PortalContainerFilter</filter-class>
</filter>  

<filter-mapping>
  <filter-name>PortalContainerFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Note

It is only possible to disable a portal container when at least one PortalContainerDefinition has been registered.

A.5. Runtime Configuration Profiles

The kernel configuration is able to handle configuration profiles at runtime (as opposed to packaging time).
An active profile list is obtained when the root container is loaded, and is composed of the system property exo.profiles sliced according the "," delimiter and a server specific profile value (tomcat for tomcat, jboss for jboss, etc...).
# runs the portal with the profiles jboss, foo and bar
sh run.sh -Dexo.profiles=foo,bar
Profile activation occurs in XML to configure object unmarshalling time. It is based on a "profile" attribute that is present on some of the XML elements of the configuration files. The configuration is based on the following rules:
  1. Any kernel element with the no profiles attribute will create a configuration object.
  2. Any kernel element having a profiles attribute containing at least one of the active profiles will create a configuration object.
  3. Any kernel element having a profiles attribute matching none of the active profiles will not create a configuration object
  4. Resolution of duplicates (such as two components of the same type) is left up to the kernel.
A <configuration> element is profiles-capable when it carries a <profiles> element.

Profiles-capable Configuration Directives

<component>
The <component> element declares a component when activated. It will shadow any element with the same key declared before in the same configuration file:
<component>
  <key>Component</key>
  <type>Component</type>
</component>

<component profiles="foo">
  <key>Component</key>
  <type>FooComponent</type>
</component>
<component-plugin>
The <component-plugin> element is used to dynamically extend the configuration of a given component. Thanks to the profiles the <component-plugin> elements can be enabled or disabled:
<external-component-plugins>
  <target-component>Component</target-component>
  <component-plugin profiles="foo">
    <name>foo</name>
    <set-method>addPlugin</set-method>
    <type>type</type>
    <init-params>
      <value-param>
        <name>param</name>
        <value>empty</value>
      </value-param>
    </init-params>
  </component-plugin>
</external-component-plugins>
<import>
The <import> element imports a referenced configuration file when activated:
<import>empty</import>
<import profiles="foo">foo</import>
<import profiles="bar">bar</import>
<init-params>
The <init-params> element configures the parameter argument of the construction of a component service:
<component>
  <key>Component</key>
  <type>ComponentImpl</type>
  <init-params>
    <value-param>
      <name>param</name>
      <value>empty</value>
    </value-param>
    <value-param profiles="foo">
      <name>param</name>
      <value>foo</value>
    </value-param>
    <value-param profiles="bar">
      <name>param</name>
      <value>bar</value>
    </value-param>
  </init-params>
</component>
<value-collection>
The <value-collection> element configures one of the value of collection data:
<object type="org.exoplatform.container.configuration.ConfigParam">
  <field name="role">
    <collection type="java.util.ArrayList">
      <value><string>manager</string></value>
      <value profiles="foo"><string>foo_manager</string></value>
      <value profiles="foo,bar"><string>foo_bar_manager</string></value>
    </collection>
  </field>
</object>
<field-configuration>
The <field-configuration> element configures the field of an object:
<object-param>
  <name>test.configuration</name>
  <object type="org.exoplatform.container.configuration.ConfigParam">
    <field name="role">
      <collection type="java.util.ArrayList">
        <value><string>manager</string></value>
      </collection>
    </field>
    <field name="role" profiles="foo,bar">
      <collection type="java.util.ArrayList">
        <value><string>foo_bar_manager</string></value>
      </collection>
    </field>
    <field name="role" profiles="foo">
      <collection type="java.util.ArrayList">
        <value><string>foo_manager</string></value>
      </collection>
    </field>
  </object>
</object-param>

A.6. Component request life cycle

A.6.1. Component request life cycle contract

The component request life cycle is an interface that defines a contract for a component for being involved into a request:
public interface ComponentRequestLifecycle
{
   /**
    * Start a request.
    * @param container the related container
    */
   void startRequest(ExoContainer container);
 
   /**
    * Ends a request.
    * @param container the related container
    */
   void endRequest(ExoContainer container);
}
The container passed is the container to which the component is related. This contract is often used to setup a thread local based context that will be demarcated by a request.
For example, a component in the portal request life cycle is triggered for user requests. Another example is the initial data import in the portal that demarcates using callbacks made to that interface.

A.6.2. Request life cycle

The RequestLifeCycle class has several statics methods that are used to schedule the component request life cycle of components. Its main responsibility is to perform scheduling while respecting the constraint to execute the request life cycle of a component only once even if it can be scheduled several times.

A.6.2.1. Scheduling a component request life cycle

RequestLifeCycle.begin(component);
try
{
   // Do something
}
finally
{
   RequestLifeCycle.end();
}

A.6.2.2. Scheduling a container request life cycle

Scheduling a container triggers the component request life cycle of all the components that implement the interface ComponentRequestLifeCycle. If one of the components has already been scheduled before, the component is not scheduled again.
If the local value is true, the looked components are those of the container. When the value is false, the scheduler looks at the components in the ancestor containers.
RequestLifeCycle.begin(container, local);
try
{
   // Do something
}
finally
{
   RequestLifeCycle.end();
}

A.6.2.3. When request life cycle is triggered

A.6.2.3.1. Portal request life cycle
Each portal request triggers the life cycle of the associated portal container.
A.6.2.3.2. JMX request Life Cycle
When a JMX bean is invoked, the request life cycle of the container to which it belongs it scheduled. Indeed JMX is an entry point of the system that may need component to have a request life cycle triggered.

A.7. Configuring Services

The eXo Kernel uses dependency injection to create services based on configuration.xml configuration files. The location of the configuration files determines if services are placed into the RootContainer scope, or into the PortalContainer scope.
When creating a service, declare its existence to the Container by creating a /conf/configuration.xml configuration file in the service's base folder. The container looks for a /conf/configuration.xml file in each jar-file.
All files located at /conf/configuration.xml in the classpath (any directory, or any jar in the classpath) will have services configured in the RootContainer scope.
All configuration.xml files located in /conf/portal/configuration.xml of the classpath will have services configured at the PortalContainer scope.
Portal extensions can also use configuration information stored in $JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/configuration.xml, and will also have their services configured in the PortalContainer scope.
When eXo kernel reads a configuration, it loads the file from the kernel jar using the classloader, and does not use an internet connection to resolve the file.

Note

Portal extensions are described later in this document.

A.7.1. Configuration syntax

A.7.1.1. Components

A service component is defined in configuration.xml by using a <component> element.
Only one piece of information is required when defining a service; the service implementation class. This is specified using <type>
Every component has a <key> element that identifies it. If not explicitly set, a key defaults to the value of <type>. If a key can be loaded as a class, a class object is used as a key, otherwise a string is used.
The typical approach is to specify an interface as a key.
<?xml version="1.0" encoding="ISO-8859-1"?>
<configuration
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd
                          http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
      xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">
   <component>
      <key>org.exoplatform.services.database.HibernateService</key>
      <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type>

      ...

   </component>
</configuration>
The configuration found inside the JAR file is considered the default configuration. The default configuration can be overridden in different places inside the JAR. When the container finds several configurations for the same service, the configuration override mechanism always loads the most recently discovered configuration file.
All custom configuration is made in the /webapps/portal/WEB-INF/conf/configuration.xml file. Use <component> elements to contain the configuration information. The <key> element defines the interface, and the <type> tag defines the implementation. While the <key> tag is not mandatory, specifying it can result in a small performance improvement.

Example A.13. <component> Custom Configuration Block

Register plug-ins that can act as listeners or external plug-in to bundle some plug-in classes in other jar modules. The usual example is the hibernate service to which HBM mapping files can be added, even if those files are deployed in another maven artifact.
<!-- Portlet container hooks -->
  <component>
    <key>org.exoplatform.services.portletcontainer.persistence.PortletPreferencesPersister</key>
    <type>org.exoplatform.services.portal.impl.PortletPreferencesPersisterImpl</type>
  </component>

Example A.14. Define Services That Can Receive Plug-ins Without a Framework Interface

Target the HibernateService and call its addPlugin() method with an argument of the type AddHibernateMappingPlugin. Init parameters for the object are already filled.
<external-component-plugins>
  <target-component>org.exoplatform.services.database.HibernateService</target-component>
  <component-plugin> 
    <name>add.hibernate.mapping</name>
    <set-method>addPlugin</set-method>
    <type>org.exoplatform.services.database.impl.AddHibernateMappingPlugin</type>
    <init-params>
      <values-param>
        <name>hibernate.mapping</name>
        <value>org/exoplatform/services/portal/impl/PortalConfigData.hbm.xml</value>
        <value>org/exoplatform/services/portal/impl/PageData.hbm.xml</value>
        <value>org/exoplatform/services/portal/impl/NodeNavigationData.hbm.xml</value>
      </values-param>        
    </init-params>
  </component-plugin>
</external-component-plugins>

Example A.15. Add Listener to the OrganizationService

The OrganizationService calls the method addListenerPlugin with an object of type PortalUserEventListenerImpl. Each time a user is created (apart the predefined ones in the list ) PortalUserEventListenerImpl methods are called by the service.
<external-component-plugins>
  <target-component>org.exoplatform.services.organization.OrganizationService</target-component>
  <component-plugin>
    <name>portal.new.user.event.listener</name>
    <set-method>addListenerPlugin</set-method>
    <type>org.exoplatform.services.portal.impl.PortalUserEventListenerImpl</type>
    <description>this listener create the portal configuration for the new user</description>
    <init-params>
      <object-param>
        <name>configuration</name>
        <description>description</description>
        <object type="org.exoplatform.services.portal.impl.NewPortalConfig">
          <field  name="predefinedUser">
            <collection type="java.util.HashSet">
              <value><string>admin</string></value>
              <value><string>exo</string></value>
              <value><string>company</string></value>
              <value><string>community</string></value>
              <value><string>portal</string></value>
              <value><string>exotest</string></value>
            </collection>
          </field>
          <field  name="templateUser"><string>template</string></field>
          <field  name="templateLocation"><string>war:/conf/users</string></field>
        </object>
      </object-param>
    </init-params>
  </component-plugin>
...
From the examples above, it is evident there are several types of init parameters available, from a simple value param which binds a key with a value to a more complex object mapping that fills a JavaBean with the info defined in the XML.
A.7.1.1.1. RootContainer
RootContainer is a dependency of PortalContainer. It is important to understand how RootContainer works because it is referred to in other containers.
Configuration retrieval occurs from the following file locations:
  1. Services default RootContainer configurations from JAR files /conf/configuration.xml
  2. External RootContainer configuration, to be found at $JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/configuration.xml
The RootContainer creates a Java HashTable which contains key-value pairs for the services. The qualified interface name of each service is used as key for the hash table. The <key> element of the configuration file contains the interface name. The value of each hash table pair is an object that contains the service configuration, which is the whole structure between the <component> tags of the configuration.xml file.
The RootContainer runs over all JAR files present in $JPP_HOME/modules/system/layers/gatein/org/gatein/lib and checks if there is a configuration file located in /conf/configuration.xml. If the file is present, the services configured in this file are added to the hash table. At the end of the boot process, the default configurations for all services are stored in the hash table.

Note

If the same service, recognized by the same qualified interface name, is configured in different JARs, the configuration defined in a JAR archive loaded after the previous JAR is used. Because the loading of or JAR files can be unpredictable, do not depend on the load order to load the correct configuration.
To provide configuration detail for one or more services, create a general configuration file located in $JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/configuration.xml. The same configuration rules that apply to JARs apply to this configuration file.
Further configuration retrieval depends on the container type.
A.7.1.1.2. PortalContainer
The PortalContainer takes the hash table filled by the RootContainer and looks in other locations. Here you get the opportunity to replace RootContainer configurations by those which are specific to your portal. Again, the configurations are overridden whenever necessary.
The PortalContainer configuration is retrieved in the following lookup sequence:
  1. Inherit the configuration of the RootContainer.
  2. Default PortalContainer configuration from all JAR files (/conf/portal/configuration.xml)
  3. Web application configurations from the portal.war file, or the portal web app configuration file (/WEB-INF/conf/configuration.xml).
  4. External configuration for services of a named portal, located in exo-tomcat/exo-conf/portal/$portal_name/configuration.xml.
The /conf/portal/configuration.xml file of each JAR are loaded as they are discovered, the last configuration file loaded being the one used for all JARs. The next file the container loads is from within the portal.war archive (or the portal webapp folder). The /WEB-INF/conf/configuration.xml contains many import statements that point to other configuration files in the same portal.war (or portal webapp).
For multiple portals, be aware that each portal may use a unique configuration.xml file in the PortalContainer. From Red Hat JBoss Portal 6.1, configuration can be provided from outside the JARs and WARs or webapps. Place a configuration file in exo-tomcat/exo-conf/portal/$portal_name/configuration.xml where $portal_name is the name of the portal to configure. In most cases, installations have one primary portal, named by default as "portal". In this scenario, the exo-tomcat/exo-conf/portal/portal/configuration.xml is used.

Note

exo-conf is looked up in directory specified by the Red Hat JBoss System property jboss.server.config.url. If the property is not found or empty, exo-jboss/exo-conf is loaded by default.

Note

As of Red Hat JBoss Portal 6.1 the system property exo.conf.dir can be used to override the external configuration location. If the property is defined, its value is used as path to the eXo configuration directory. This is an alternative method of loading configuration in the exo-tomcat/exo-conf folder.
When starting the portal, add the property in the command line: java -Dexo.conf.dir=/path/to/exo/conf, or use eXo.bat or eXo.sh.
In this particular use case, it is not necessary to use any prefixes in the configuration file to import other files. For example, if the standard configuration file is located in exo-tomcat/exo-conf/portal/PORTAL_NAME/configuration.xml and the target configuration file located in exo-tomcat/exo-conf/portal/PORTAL_NAME/mySubConfDir/myConfig.xml must be loaded, add <import>mySubConfDir/myConfig.xml</import> to the configuration file.
A.7.1.1.3. External Plug-ins
The eXo Kernel supports non-component objects that can be configured, instantiated, and injected into registered components using method calls. This plug-in method allows portal extensions to add additional configuration to core services.
An external plug-in is defined by using the <external-component-plugin> wrapper element, which contains one or more <component-plugin> definitions.
The <external-component-plugin> element uses <target-component> to specify a target service component that will receive injected objects.
Every <component-plugin> defines an implementation type, and a method on the target component to use for injection (<set-method>).
A plug-in implementation class has to implement the org.exoplatform.container.component.ComponentPlugin interface.
In the following example the PortalContainerDefinitionPlugin implements the ComponentPlugin:
<?xml version="1.0" encoding="UTF-8"?>
<configuration
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd
                          http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
      xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">

   <external-component-plugins>
      <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>
      <component-plugin>
         <!-- The name of the plug-in -->
         <name>Add PortalContainer Definitions</name>

         <!-- The name of the method to call on the PortalContainerConfig
              in order to register the PortalContainerDefinitions -->
         <set-method>registerPlugin</set-method>

         <!-- The fully qualified name of the PortalContainerDefinitionPlugin -->
         <type>org.exoplatform.container.definition.PortalContainerDefinitionPlugin</type>

         ...

      </component-plugin>
   </external-component-plugins>
</configuration>
The <target-component> defines the service for which the plug-in is defined. The configuration is injected by the container using a method that is defined in <set-method>. The method has one argument of the type org.exoplatform.services.cms.categories.impl.TaxonomyPlugin:
  • addTaxonomyPlugin(org.exoplatform.services.cms.categories.impl.TaxonomyPlugin plugin)
The content of <init-params> corresponds to the structure of the TaxonomyPlugin object.

Note

The CategoriesService component can be configured using the addTaxonomyPlugin as often as required. addTaxonomyPlugin can also be called in different configuration files. The method addTaxonomyPlugin is then called several times: everything else depends on the implementation of the method.
A.7.1.1.4. Service instantiation
All services are singletons: the container creates only one single instance of each container. The services are created by calling the constructors, the process of which is referred to as constructor injection).

Example A.16. Service Instantiation

The JDBC implementation of the BaseOrganizationService interface contained in OrganizationServiceImpl.java [1] file has one constructor only.
This service depends on two other services. To call this constructor, the container requires a ListenerService and a DatabaseService. These services must be instantiated before BaseOrganizationService, because BaseOrganizationService depends on them.
public OrganizationServiceImpl(ListenerService listenerService, DatabaseService dbService);
To execute the service instantiation required in Example A.16, “Service Instantiation”, dependencies are injected by the container. The container first looks at the constructors of all services and creates a matrix of service dependencies in order to call the services in the correct order. If for any reason there are interdependencies or circular dependencies detected, a java.lang.Exception is thrown.

Note

If one service has more than one constructor, the container attempts to use the constructor with a maximum of arguments first. If this is not possible, the container continues step by step with constructors that have less arguments until arriving at the zero-argument constructor (if there is one).
A.7.1.1.5. Service Access
To maintain Inversion of Control (IoC) principles, a container must be used when accessing a service. Accessing a service directly does not conform with IoC requirements.
To get the current container, use the ExoContainer myContainer = ExoContainerContext.getCurrentContainer(); command.
To retrieve a configured service, use the myContainer.getComponentInstance(class) method.

Example A.17. Service Access Command and Method Usage

ArticleStatsService statsService = (ArticleStatsService) myContainer.getComponentInstance(ArticleStatsService.class);

Example A.18. 

package com.laverdad.common;

import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.ExoContainerContext;
import com.laverdad.services.*;

public class Statistics {

  public int makeStatistics(String articleText) {
    ExoContainer myContainer = ExoContainerContext.getCurrentContainer();
    ArticleStatsService statsService = (ArticleStatsService)
        myContainer.getComponentInstance(ArticleStatsService.class);    
    int numberOfSentences = statsService.calcSentences(articleText);
    return numberOfSentences;
  }
  
  public static void main( String args[]) {
   Statistics stats = new Statistics();
   String newText = "This is a normal text. The method only counts the number of periods. "
   + "You can implement your own implementation with a more exact counting. "
   + "Let`s make a last sentence.";
  System.out.println("Number of sentences: " + stats.makeStatistics(newText));
  }
}
A.7.1.1.6. Includes, and special URLs
It is possible to divide the configuration.xml file into many smaller files, which are then included into the main configuration file.
The included files must be valid XML files: fragments of text in the referenced files will cause load issues.

Example A.19. Outsourcing Configuration to External Files

<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd
                          http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
      xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">
   <!-- Comment #1 -->
   <import>war:/conf/sample-ext/jcr/jcr-configuration.xml</import>
   <import>war:/conf/sample-ext/portal/portal-configuration.xml</import>

</configuration>
Comment #1: This line specifies the location of another configuration file. The war: URL schema indicates the path is resolved relative to the current PortalContainer's servlet context resource path, starting with /WEB-INF as the root.

Note

The current PortalContainer is a newly created PortalContainer, because war: URLs are used for PortalContainer scoped configuration only.
To have an 'include' path resolved relative to current classpath (context classloader), use a 'jar:' URL schema.
Through the extension mechanism, the servlet context used for resource loading is a unified servlet context (this is explained in a later section).
A.7.1.1.7. Special variables
Configuration files may contain a ${container.name.suffix} special variable reference. This variable resolves to the name of the current portal container, prefixed by underscore (_).
This facilitates reuse of configuration files in situations where portal-specific unique names need to be assigned to certain resources: JNDI names, Database/DataSource names, and JCR repository names.
This variable is only defined when there is a current PortalContainer available, and is only available for PortalContainer scoped services.

Example A.20. ${container.name.suffix} Usage

<?xml version="1.0" encoding="ISO-8859-1"?>
...
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
               xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">
...
  <component>
    <key>org.exoplatform.services.database.HibernateService</key>
    <jmx-name>database:type=HibernateService</jmx-name>
    <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type>
    <init-params>
      <properties-param>
        <name>hibernate.properties</name>
        <description>Default Hibernate Service</description>
        <property name="hibernate.cache.region.jbc2.query.localonly" value="true" />
        <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory" />
        <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
        <property name="hibernate.show_sql" value="false"/>
        <property name="hibernate.current_session_context_class" value="thread"/>
        <property name="hibernate.cache.use_second_level_cache" value="true"/>
        <property name="hibernate.cache.use_query_cache" value="true"/>
        <property name="hibernate.connection.datasource" value="${gatein.idm.datasource.name}${container.name.suffix}"/>
        <property name="hibernate.connection.autocommit" value="true"/>
        <!--
        	Should be automatically detected. Force otherwise 
        <property name="hibernate.dialect" value="org.hibernate.dialect.XXXDialect"/>
         -->
      </properties-param>
    </init-params>
  </component>
...
</configuration>

A.7.1.2. <init-params> configuration element

<init-params> is a configuration element that contains a map of key-value pairs, where the key is always a String, and the value can be any type that can be described using the kernel XML configuration.
Service components that form the portal infrastructure use <init-params> to define the configuration. A component can have one instance of <init-params> injected at most.
If the service component's constructor takes <init-params> as any of the parameters, it will be injected at component instantiation time.
The <init-params> structure (the names and types of entries) is specific for each service, as it is the code inside a service components' class that defines which entry names to look up and what types it expects to find.
The XML configuration for a service component that expects an <init-params> element must have an <init-params> element present, however this element can be left empty.

Example A.21. <init-params> XML Configuration and Parameter Descriptions

<component>
 <key>org.exoplatform.services.naming.InitialContextInitializer</key>
 <type>org.exoplatform.commons.InitialContextInitializer2</type>
 <init-params>
   <properties-param>
     <name>default-properties</name>
     <description>Default initial context properties</description>
   </properties-param>
 </init-params>
</component>
An <init-params> element can have zero or more children elements, each of which is one of the following:
  • <value-param>
  • <values-param>
  • <properties-param>
  • <object-param>
Each child element uses a <name> element that is used as a map entry key, and an optional <description> element. It also takes a type-specific value specification.
The value specification for the <properties-param> defines one or more <property> elements, each of which specifies two strings; a property name and a property value.
Each <properties-params> defines one java.util.Properties instance.

Example A.22. <value-param> Example

  <component>
    <key>org.exoplatform.portal.config.UserACL</key>
    <type>org.exoplatform.portal.config.UserACL</type>   
    <init-params>      
...
      <value-param>
        <name>access.control.workspace</name>
        <description>groups with memberships that have the right to access the User Control Workspace</description>
        <value>*:/platform/administrators,*:/organization/management/executive-board</value> 
      </value-param> 
...
  </component>
The UserACL class accesses to the <value-param> in its constructor.
package org.exoplatform.portal.config;
public class UserACL {

  public UserACL(InitParams params) {
    UserACLMetaData md = new UserACLMetaData();
    ValueParam accessControlWorkspaceParam = params.getValueParam("access.control.workspace");
    if(accessControlWorkspaceParam != null) md.setAccessControlWorkspace(accessControlWorkspaceParam.getValue());
...

Example A.23. <values-param> XML Configuration and Parameter Descriptions

The value specification for <value-param> elements is a <value> element which defines a String instance.
<component>
  <key>org.exoplatform.services.resources.ResourceBundleService</key>
  <type>org.exoplatform.services.resources.impl.SimpleResourceBundleService</type>
    <init-params>
      <values-param>
        <name>classpath.resources</name>
        <description>The resources  that start with the following package name should be load from file system</description>
        <value>locale.portlet</value>
      </values-param>

      <values-param>
        <name>init.resources</name>
        <description>Store the following resources into the db for  the first launch </description>
        <value>locale.test.resources.test</value>
      </values-param>

      <values-param>
        <name>portal.resource.names</name>
        <description>The properties files of  the portal ,  those file will be merged
          into one ResourceBundle properties </description>
        <value>local.portal.portal</value>
        <value>local.portal.custom</value>
      </values-param>
    </init-params>
</component>
The value specification for <values-param> requires one or more <value> elements. Each <value> represents one String instance. All String values are then collected into a java.util.List instance.

Example A.24. <properties-param> Hibernate Example


<component>
  <key>org.exoplatform.services.database.HibernateService</key>
  <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type>
  <init-params>
    <properties-param>
      <name>hibernate.properties</name>
      <description>Default Hibernate Service</description>
      <property name="hibernate.show_sql" value="false"/>
      <property name="hibernate.cglib.use_reflection_optimizer" value="true"/>
      <property name="hibernate.connection.url" value="jdbc:hsqldb:file:../temp/data/exodb"/>
      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
...
    </properties-param>
  </init-params>
</component>
In the org.exoplatform.services.database.impl.HibernateServiceImpl, the name hibernate.properties of the <properties-param> is used to access the properties.
package org.exoplatform.services.database.impl;

public class HibernateServiceImpl implements HibernateService, ComponentRequestLifecycle {
  public HibernateServiceImpl(InitParams initParams, CacheService cacheService) {
    PropertiesParam param = initParams.getPropertiesParam("hibernate.properties");
...
}

Example A.25. <object-param> XML Configuration and Parameter Descriptions

<component>
   <key>org.exoplatform.services.cache.CacheService</key>
   <jmx-name>cache:type=CacheService</jmx-name>
   <type>org.exoplatform.services.cache.impl.CacheServiceImpl</type>
   <init-params>
      <object-param>
         <name>cache.config.default</name>
         <description>The default cache configuration</description>
         <object type="org.exoplatform.services.cache.ExoCacheConfig">
            <field name="name">
               <string>default</string>
            </field>
            <field name="maxSize">
               <int>300</int>
            </field>
            <field name="liveTime">
               <long>300</long>
            </field>
            <field name="distributed">
               <boolean>false</boolean>
            </field>
            <field name="implementation">
               <string>org.exoplatform.services.cache.concurrent.ConcurrentFIFOExoCache</string>
            </field>
         </object>
      </object-param>
   </init-params>
</component>
For <object-param> entries, the value specification consists of an <object> element which is used for plain Java style object specification (specifying an implementation class - <type>, and property values - <field>).

Example A.26. <object-param> and LDAP Example


<component>
  <key>org.exoplatform.services.LDAP.LDAPService</key>
  <type>org.exoplatform.services.LDAP.impl.LDAPServiceImpl</type>
  <init-params>
    <object-param>
      <name>LDAP.config</name>
      <description>Default LDAP config</description>
      <object type="org.exoplatform.services.LDAP.impl.LDAPConnectionConfig">         
        <field  name="providerURL">
          <string>LDAPs://10.0.0.3:636</string>
        </field>
        <field  name="rootdn">
          <string>CN=Administrator,CN=Users,DC=exoplatform,DC=org</string>
        </field>
        <field  name="password">
          <string>exo</string>
        </field>
        <field  name="version">
          <string>3</string>
        </field>
        <field  name="minConnection">
          <int>5</int>
        </field>
        <field  name="maxConnection">
          <int>10</int>
        </field>    
        <field  name="referralMode">
          <string>ignore</string>
        </field>
        <field  name="serverName">
          <string>active.directory</string>
        </field>
      </object>
    </object-param>
  </init-params>
</component>
It is not important to understand LDAP for this example: only the parameters as they relate to <object-param> are discussed.
An <object-param> element is used to pass the parameters inside an object (a java bean). It consists of the following elements:
  • <name>
  • <description>
  • <object>, which defines the type and a number of <field> elements.
The service accesses the object in the following way:

package org.exoplatform.services.LDAP.impl;

public class LDAPServiceImpl implements LDAPService {
...
  public LDAPServiceImpl(InitParams params) {
    LDAPConnectionConfig config = (LDAPConnectionConfig) params.getObjectParam("LDAP.config")
                                                               .getObject();
...
The passed object is LDAPConnectionConfig, which is a Java bean. It contains all fields and also the appropriate getters and setters (not listed here). Default values can also be provided. The container creates a new instance of the bean, and calls all setters whose values are configured in the configuration file.
package org.exoplatform.services.LDAP.impl;

public class LDAPConnectionConfig {
  private String providerURL        = "LDAP://127.0.0.1:389";
  private String rootdn;
  private String password;                                  
  private String version;                                   
  private String authenticationType = "simple";
  private String serverName         = "default";
  private int    minConnection;
  private int    maxConnection;
  private String referralMode       = "follow";
...
The types (String, int) of the fields in the configuration correspond with the bean. The kernel_1_2.xsd file also shows some simple types:
  • string, int, long, boolean, date, double
The object.xml resources file shows the complete list of types, : https://anonsvn.jboss.org/repos/exo-jcr/kernel/trunk/exo.kernel.container/src/test/resources/object.xml.
<object type="package.name">
  <field  name="string"><string>This is a string</string></field>
  <field  name="int"><int>1234</int></field>
  <field  name="long"><long>123456</long></field>
  <field  name="double"><double>1.1234</double></field>
  <field  name="boolean"><boolean>true</boolean></field>
  <field  name="name">
    <object version="1.0" type="package.name">
      <field  name="nested 1"><string>value</string></field>
      <field  name="nested 2"><int>1234</int></field>
    </object>
  </field>
  <field  name="map">
    <map type="java.util.HashMap">
      <entry>
        <key><string>akey</string></key>
        <value><string>a value</string></value>
      </entry>
      <entry>
        <key><int>1234</int></key>
        <value><string>a value</string></value>
      </entry>
    </map>
  </field>
  <field  name="list">
    <collection type="java.util.ArrayList">
      <value><string>a value</string></value>
    </collection>
  </field>
</object>
		
A.7.1.2.1. Collection
Java collections can be used to configure a service. Open the database-organization-configuration.xml file as an example configuration. This file defines a default user organization (users, groups, memberships/roles) of the portal. The configuration uses <component-plugins> elements, and the <object-param> element is also used.
There are two collections: The first collection is an ArrayList, which contains one value: the object which defines the field of the NewUserConfig$JoinGroup bean.
The second collection is a HashSet that is a set of strings.
    <component-plugin>
      <name>new.user.event.listener</name>
      <set-method>addListenerPlugin</set-method>
      <type>org.exoplatform.services.organization.impl.NewUserEventListener</type>
      <description>this listener assign group and membership to a new created user</description>
      <init-params>
        <object-param>
          <name>configuration</name>
          <description>description</description>
          <object type="org.exoplatform.services.organization.impl.NewUserConfig">
            <field  name="group">
              <collection type="java.util.ArrayList">
                <value>
                  <object type="org.exoplatform.services.organization.impl.NewUserConfig$JoinGroup">
                    <field  name="groupId"><string>/platform/users</string></field>
                    <field  name="membership"><string>member</string></field>
                  </object>
                </value>               
              </collection>
            </field>
            <field  name="ignoredUser">
              <collection type="java.util.HashSet">
                <value><string>root</string></value>
                <value><string>john</string></value>
                <value><string>marry</string></value>
                <value><string>demo</string></value>
                <value><string>james</string></value>
              </collection>
            </field>
          </object>
        </object-param>
      </init-params>
    </component-plugin>
The org.exoplatform.services.organization.impl.NewUserConfig bean is a good example to showcase the HashSet:
public class NewUserConfig {
  private List    role;
  private List    group;
  private HashSet ignoredUser;

  ...

  public void setIgnoredUser(String user) {
    ignoredUser.add(user);

  ...

  static public class JoinGroup {
    public String  groupId;
    public String  membership;
  ...
}
The values of the HashSet are set one by one by the container. It is the responsibility of the bean to add these values to its HashSet.
The JoinGroup object is an inner class and implements a bean of its own. It can be accessed like any other inner class using NewUserConfig.JoinGroup.

A.7.1.3. Component Plug-in Priority

It is possible to setup loading order for ComponentPlugin directives. Use the <priority> element to define the plug-in load priority. All plug-ins get priority '0' by default: they are loaded in the container's normal method. To load one plug-in later than the others, set the priority for it higher than zero.
Simple example of fragment of a configuration.xml.

Example A.27. <priority> Element

...
<component>
  <type>org.exoplatform.services.Component1</type>
</component>

<external-component-plugins>
  <target-component>org.exoplatform.services.Component1</target-component>

  <component-plugin>
    <name>Plugin1</name>
    <set-method>addPlugin</set-method>
    <type>org.exoplatform.services.plugins.Plugin1</type>
    <description>description</description>
    <priority>1</priority>
  </component-plugin>

  <component-plugin>
    <name>Plugin2</name>
    <set-method>addPlugin</set-method>
    <type>org.exoplatform.services.plugins.Plugin2</type>
    <description>description</description>
    <priority>2</priority>
  </component-plugin>

</external-component-plugins>

<external-component-plugins>
  <target-component>org.exoplatform.services.Component1</target-component>
  <component-plugin>
    <name>Plugin3</name>
    <set-method>addPlugin</set-method>
    <type>org.exoplatform.services.plugins.Plugin3</type>
    <description>description</description>
  </component-plugin>
</external-component-plugins>
...
The plug-in 'Plugin3' is loaded first because it has the default priority '0'. Plug-in 'Plugin1' is loaded and then plug-in 'Plugin2'.

A.7.1.4. Configuration Logging

The JVM system property org.exoplatform.container.configuration.debug can assist with identifying problems with service configuration, by identifying the JAR/WAR that is causing issues. Add the system property to the eXo.bat or eXo.sh file in the exo-tomcat/bin/ directory.
set EXO_CONFIG_OPTS="-Dorg.exoplatform.container.configuration.debug"
If this property is set, the container configuration manager reports during startup the configuration retrieval process to the standard output (System.out).
......
Add configuration jar:file:/D:/Projects/eXo/dev/exo-working/exo-tomcat/lib/exo.kernel.container-trunk.jar!/conf/portal/configuration.xml
Add configuration jar:file:/D:/Projects/eXo/dev/exo-working/exo-tomcat/lib/exo.kernel.component.cache-trunk.jar!/conf/portal/configuration.xml
Add configuration jndi:/localhost/portal/WEB-INF/conf/configuration.xml import jndi:/localhost/portal/WEB-INF/conf/common/common-configuration.xml
import jndi:/localhost/portal/WEB-INF/conf/database/database-configuration.xml import jndi:/localhost/portal/WEB-INF/conf/ecm/jcr-component-plugins-configuration.xml
import jndi:/localhost/portal/WEB-INF/conf/jcr/jcr-configuration.xml
......

A.7.1.5. Import

Use the import tag to reference other configuration files from within the configuration.xml file. The imported files can be placed anywhere on the system, providing the files can be accessed by the user configured on the host machine.

Important

If a default configuration file is packaged as part of the JAR/WAR, do not import files external to the JAR/WAR.
  • war: Imports from portal.war/WEB-INF
  • jar or classpath: Uses the classloader. Use this prefix in the default configuration for importing another configuration file accessible by the classloader.
  • file: Uses an absolute path. A URL is also a valid value for this parameter.
  • without any prefix:
The $JPP_HOME/gatein/gatein.ear/portal.war/WEB-INF/conf/configuration.xml file contains import statements primarily:
<import>war:/conf/common/common-configuration.xml</import>
<import>war:/conf/common/logs-configuration.xml</import>
<import>war:/conf/database/database-configuration.xml</import>
<import>war:/conf/jcr/jcr-configuration.xml</import>
<import>war:/conf/common/portlet-container-configuration.xml</import>
...

A.7.1.6. System properties

System properties can be used in literal values of component configuration metadata. This makes it possible to resolve properties at runtime instead of providing a value at packaging time.

Example A.28. System Property

The /web/portal/src/main/webapp/WEB-INF/conf/database/database-configuration.tmpl.xml shows how system properties are used in configuration.
  
<component>
  <key>org.exoplatform.services.database.HibernateService</key>
  <jmx-name>database:type=HibernateService</jmx-name>
  <type>org.exoplatform.services.database.impl.HibernateServiceImpl</type>
  <init-params>
    <properties-param>
      <name>hibernate.properties</name>
      <description>Default Hibernate Service</description>
...
      <property name="hibernate.connection.url" value="${connectionUrl}"/>
      <property name="hibernate.connection.driver_class" value="${driverClass}"/>
      <property name="hibernate.connection.username" value="${username}"/>
      <property name="hibernate.connection.password" value="${password}"/>
      <property name="hibernate.dialect" value="${dialect}"/>
...
    </properties-param>
  </init-params>
</component>

Note

System properties require the -D command in the start up command: java -DconnectionUrl=jdbc:hsqldb:file:../temp/data/exodb -DdriverClass=org.hsqldb.jdbcDriver.
Alternatively, specify the command in the .bat or .sh portal start script, which will load the configuration each time the portal is started: set EXO_OPTS="-DconnectionUrl=jdbc:hsqldb:file:../temp/data/exodb -DdriverClass=org.hsqldb.jdbcDriver"

A.8. Specific Services

A.8.1. ListenerService

Inside eXo, an event mechanism allows to trigger and listen to events under specific conditions. This mechanism is used in several places in eXo such as login/logout time.
Listeners must be subclasses of org.exoplatform.services.listener.Listener registered by the ListenerService.

A.8.1.1. Configuring a Listener

All listeners are a ComponentPlugin. The following configuration is required:
<?xml version="1.0" encoding="ISO-8859-1"?>
<configuration>
...
  <external-component-plugins>
    <!-- The full qualified name of the ListenerService --> 
    <target-component>org.exoplatform.services.listener.ListenerService</target-component>

    <component-plugin>
    <!-- The name of the listener that is also the name of the target event -->
      <name>${name-of-the-target-event}</name>
      <!-- The name of the method to call on the ListenerService in order to register the Listener -->
      <set-method>addListener</set-method>
      <!-- The full qualified name of the Listener -->
      <type>${the-FQN-of-the-listener}</type>
    </component-plugin>

  </external-component-plugins>
</configuration>

A.8.1.2. Registering a Listener

To register a listener, call the addListener() method.
/**
 * This method is used to register a listener with the service. The method
 * will: 1. Check to see if there is a list of listener with the listener
 * name, create one if the listener list doesn't exit 2. Add the new listener
 * to the listener list
 * 
 * @param listener
*/
public void addListener(Listener listener) {
   ...
}
By convention, the listener name is declared as the name of the event to listen for.

A.8.1.3. Triggering an Event

To trigger an event, an application can call one of the broadcast() methods of ListenerService.
/**
 * This method is used to broadcast an event. This method will: 1. Check if
 * there is a list of listener that listen to the event name. 2. If there is a
 * list of listener, create the event object with the given name , source and
 * data 3. For each listener in the listener list, invoke the method
 * onEvent(Event)
 * 
 * @param <S> The type of the source that broadcast the event
 * @param <D> The type of the data that the source object is working on
 * @param name The name of the event
 * @param source The source object instance
 * @param data The data object instance
 * @throws Exception 
 */
public <S, D> void broadcast(String name, S source, D data) throws Exception {
   ...
}

/**
 * This method is used when a developer neeeds to implement his own event object
 * and broadcast the event. The method will: 1. Check if there is a list of
 * listener that listen to the event name. 2. If there is a list of the
 * listener, For each listener in the listener list, invoke the method
 * onEvent(Event)
 * 
 * @param <T> The type of the event object, the type of the event object has
 *          to be extended from the Event type
 * @param event The event instance
 * @throws Exception
 */
public <T extends Event> void broadcast(T event) throws Exception {
   ...
}
The broadcast() methods retrieve the name of the event, finds the registered listeners with the same name, and calls the onEvent() method on each listener found.
Each listener is a class that extends org.exoplatform.services.listener.Listener, as described below:
public abstract class Listener<S, D> extends BaseComponentPlugin {

   /**
    * This method should be invoked when an event with the same name is
    * broadcasted
    */
   public abstract void onEvent(Event<S, D> event) throws Exception;
}

Warning

Generics are used to limit the source of the event to the type 'S', and the data of the event to the type 'D'. It is expected that listeners implement the onEvent() method with the corresponding types.
Each listener is also a ComponentPlugin with a name and a description. Therefore, the name of the listener is the name specified in the configuration file.
public interface ComponentPlugin {
   public String getName();

   public void setName(String name);

   public String getDescription();

   public void setDescription(String description);
}

A.8.1.4. Asynchronous Event Broadcast

In previous releases, ListenerService stored Listeners and broadcasted events to them. ListenerService event broadcasting takes destination listeners, and executes events on those listeners.
Because some events may take longer to complete, enabling event processing asynchronous can lead to a performance improvement.
To make a listener asynchronous, mark the Listener implementation as @Asynchronous.
@Asynchronous
class AsynchListenerWithException<S,D> extends Listener<S,D>
{
   @Override
   public void onEvent(Event<S,D> event) throws Exception
   {
      // some expensive operation
   }
}
The AsynchListener is now executed in a separate thread by ExecutorService.
By default, the ExecutorService is configured with thread pool size 1, which can be changed in the configuration file.
   
<component>
  <key>org.exoplatform.services.listener.ListenerService</key>
  <type>org.exoplatform.services.listener.ListenerService</type>
  
  <init-params>
     <value-param>
        <name>asynchPoolSize</name>
        <value>5</value>
     </value-param>
  </init-params>
</component>

A.8.1.5. ListenerService Example

The org.exoplatform.services.security.ConversationRegistry uses the ListenerService to notify that a user has signed in or left the application. When a user signs in, the following code is called:
listenerService.broadcast("exo.core.security.ConversationRegistry.register", this, state);
This code creates a new event named exo.core.security.ConversationRegistry.register, the source of which is the current instance of ConversationRegistry, and the data is that of the given state. The ListenerService calls the method onEvent(Event<ConversationRegistry, ConversationState> event) on all listeners with the name exo.core.security.ConversationRegistry.register.

Example A.29. Define a ConversationRegistry.register Listener

Define a Listener that will listen for the event exo.core.security.ConversationRegistry.register.
<?xml version="1.0" encoding="ISO-8859-1"?>
<configuration>
...
  <external-component-plugins>
    <!-- The full qualified name of the ListenerService --> 
    <target-component>org.exoplatform.services.listener.ListenerService</target-component>

    <component-plugin>
      <!-- The name of the listener that is also the name of the target event -->
      <name>exo.core.security.ConversationRegistry.register</name>
      <!-- The name of the method to call on the ListenerService in order to register the Listener -->
      <set-method>addListener</set-method>
      <!-- The full qualified name of the Listener -->
      <type>org.exoplatform.forum.service.AuthenticationLoginListener</type>
    </component-plugin>

  </external-component-plugins>
</configuration>
...

A.8.2. Job Scheduler

Job scheduler defines a job to execute a given number of times during a given period. It is a service that is in charge of unattended background executions, commonly known for historical reasons as batch processing. It is used to create and run jobs automatically and continuously, to schedule event-driven jobs, and reports.
Jobs are scheduled to run when a given Trigger occurs. Triggers can be created with nearly any combination of the following directives:
  • at a certain time of day (to the millisecond)
  • on certain days of the week
  • on certain days of the month
  • on certain days of the year
  • not on certain days listed within a registered Calendar (such as business holidays)
  • repeated a specific number of times
  • repeated until a specific time/date
  • repeated indefinitely
  • repeated with a delay interval
Jobs are given names by their creator and can also be organized into named groups. Triggers may also be given names and placed into groups, in order to easily organize them within the scheduler. Jobs can be added to the scheduler once, but registered with multiple Triggers. Within a J2EE environment, Jobs can perform their work as part of a distributed (XA) transaction.

A.8.2.1. Using the Job Scheduler Service in the Kernel

The kernel leverages Quartz for its scheduler service and wraps org.quartz.Scheduler in org.exoplatform.services.scheduler.impl.QuartzSheduler for easier service wiring and configuration. To work with Quartz in Kernel, the org.exoplatform.services.scheduler.JobSchedulerService class (implemented by org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl is primarily used.
To use JobSchedulerService, configure it as a component in the configuration.xml file. Because JobSchedulerService requires QuartzSheduler and QueueTasks, these two components must also be configured.
<?xml version="1.0" encoding="UTF-8"?>
<configuration
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
  xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">

  <component>
    <type>org.exoplatform.services.scheduler.impl.QuartzSheduler</type>
  </component>

  <component>
    <type>org.exoplatform.services.scheduler.QueueTasks</type>
  </component>

  <component>
    <key>org.exoplatform.services.scheduler.JobSchedulerService</key>
    <type>org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl</type>
  </component>

</configuration>

A.8.2.2. Samples

Work with JobSchedulerService by creating a sample project, and use the portal for testing.
The kernel makes it easier to work with job scheduler service. Implement the org.quartz.Job interface and add the job class to perform.

Procedure A.1. Prepare Job Scheduler Project

  1. Create a project by using the maven archetype plug-in. Run the mvn archetype:generate command to create a sample project.
    • For project type: select maven-archetype-quickstart.
    • For groupId: select org.exoplatform.samples.
    • For artifactId: select exo.samples.scheduler.
    • For version: select 1.0.0-SNAPSHOT.
    • For package: select org.exoplatform.samples.scheduler.
    <project
      xmlns="http://maven.apache.org/POM/4.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    
      <modelVersion>4.0.0</modelVersion>
    
      <parent>
        <artifactId>exo.portal.parent</artifactId>
        <groupId>org.exoplatform.portal</groupId>
        <version>3.1.0-GA</version>
      </parent>
    
      <groupId>org.exoplatform.samples</groupId>
      <artifactId>exo.samples.scheduler</artifactId>
      <version>1.0.0-SNAPSHOT</version>
      <name>eXo Samples For Scheduler</name>
      <description>eXo Samples Code For Scheduler</description>
    </project>
  2. Generate an eclipse project by using maven eclipse plug-in and then import into eclipse:
    mvn eclipse:eclipse
A.8.2.2.1. Define a Job
Define the job to be performed. For example, the job SampleJob is defined as follows:
package org.exoplatform.samples.scheduler.jobs;

import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * SampleJob for executing a defined sample job.
 */
public class SampleJob implements Job {

  /**
   * The logger
   */
  private static final Log LOG = ExoLogger.getLogger(SampleJob.class);

  /**
   * The job of the SampleJob will be done by executing this method.
   *
   * @param context
   * @throws JobExecutionException
   */
  public void execute(JobExecutionContext context) throws JobExecutionException {
    LOG.info("SampleJob is executing...");
  }
}
All jobs must implement the execute method from org.quartz.Job interface. This method is called whenever a job is performed. With SampleJob, logging is used to verify the job is working. By looking at the terminal, the log message "SampleJob is executing..." is displayed.
A.8.2.2.2. Configuring a Job
After defining the job, it must be configured using the <external-component-plugin> configuration for org.exoplatform.services.scheduler.JobSchedulerService. Use the following methods for setting the component plug-in:
public void addPeriodJob(ComponentPlugin plug-in) throws Exception;
The component plug-in for this method must be org.exoplatform.services.scheduler.PeriodJob. This type of job is used to perform actions that are executed over a period of time, by defining when the job is performed, when it ends, when it performs the first action, how many times it is executed and the period of time to perform the action.

Example A.30. PeriodJob <component-plugin>

<external-component-plugins>
   <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component>
    <component-plugin>
      <name>PeriodJob Plugin</name>
      <set-method>addPeriodJob</set-method>
      <type>org.exoplatform.services.scheduler.PeriodJob</type>
      <description>period job configuration</description>
      <init-params>
        <properties-param>
          <name>job.info</name>
          <description>dumb job executed  periodically</description>
          <property name="jobName" value="DumbJob"/>
          <property name="groupName" value="DumbJobGroup"/>
          <property name="job" value="org.exoplatform.samples.scheduler.jobs.DumbJob"/>
          <property name="repeatCount" value="0"/>
          <property name="period" value="60000"/>
          <property name="startTime" value="+45"/>
          <property name="endTime" value=""/>
        </properties-param>
      </init-params>
    </component-plugin>
 </external-component-plugins>

Example A.31. addCronJob

The component plug-in for this method must be org.exoplatform.services.scheduler.CronJob. This type of job is used to perform actions at a specified time, using Unix 'cron-like' definitions. The plug-in uses the expression parameter to specify the 'cron-like' definitions to execute the job.

cron-line Examples

At 12pm every day
"0 0 12 * * ?"
10:15am every Monday, Tuesday, Wednesday, Thursday and Friday
"0 15 10 ? * MON-FRI"

Note

For more information about CRON expressions, see the article at http://en.wikipedia.org/wiki/CRON_expression.
public void addCronJob(ComponentPlugin plugin) throws Exception;
<external-component-plugins>
    <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component>
    <component-plugin>
      <name>CronJob Plugin</name>
      <set-method>addCronJob</set-method>
      <type>org.exoplatform.services.scheduler.CronJob</type>
      <description>cron job configuration</description>
      <init-params>
        <properties-param>
          <name>job.info</name>
          <description>dumb job executed by cron expression</description>
          <property name="jobName" value="DumbJob"/>
          <property name="groupName" value="DumbJobGroup"/>
          <property name="job" value="org.exoplatform.samples.scheduler.jobs.DumbJob"/>
          <!-- The job will be performed at 10:15am every day -->
          <property name="expression" value="0 15 10 * * ?"/> 
        </properties-param>
      </init-params>
    </component-plugin>
  </external-component-plugins>

Example A.32. addGlobalJobListener and addJobListener

The component plug-in for these methods must be org.quartz.JobListener. This job listener is informed when org.quartz.JobDetail executes.
public void addGlobalJobListener(ComponentPlugin plugin) throws Exception;
public void addJobListener(ComponentPlugin plugin) throws Exception;

Example A.33. addGlobalTriggerListener and addTriggerListener

The component plug-in for these methods must be org.quartz.TriggerListener. This trigger listener is informed when a org.quartz.Trigger executes.
public void addGlobalTriggerListener(ComponentPlugin plugin) throws Exception;
public void addTriggerListener(ComponentPlugin plugin) throws Exception;
A.8.2.2.3. Run the Project
Create a conf.portal package in the sample project. Add the configuration.xml file with the content as follows:
<?xml version="1.0" encoding="UTF-8"?>
<configuration
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
  xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">

  <component>
    <type>org.exoplatform.services.scheduler.impl.QuartzSheduler</type>
  </component>
  <component>
    <type>org.exoplatform.services.scheduler.QueueTasks</type>
  </component>
  <component>
    <key>org.exoplatform.services.scheduler.JobSchedulerService</key>
    <type>org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl</type>
  </component>

  <external-component-plugins>
    <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component>
    <component-plugin>
      <name>PeriodJob Plugin</name>
      <set-method>addPeriodJob</set-method>
      <type>org.exoplatform.services.scheduler.PeriodJob</type>
      <description>period job configuration</description>
      <init-params>
        <properties-param>
          <name>job.info</name>
          <description>sample job executed periodically</description>
          <property name="jobName" value="SampleJob"/>
          <property name="groupName" value="SampleJobGroup"/>
          <property name="job" value="org.exoplatform.samples.scheduler.jobs.SampleJob"/>
          <property name="repeatCount" value="0"/>
          <property name="period" value="60000"/>
          <property name="startTime" value="+45"/>
          <property name="endTime" value=""/>
        </properties-param>
      </init-params>
    </component-plugin>
  </external-component-plugins>
</configuration>
mvn clean install the project, and copy the .jar file to the /lib directory in the portal directory. Run bin/run.sh to see the SampleJob to be executed on the terminal when portal containers are initialized. Review the terminal to see the log message of SampleJob.
From this point on, a job can be executed in the portal by defining the job and configuring it.

A.8.3. The data source provider

A.8.3.1. DataSourceProvider

The DataSourceProvider is a service used to give access to a data source in an uniform manner, to support data sources that are managed by the application server.

Parameters

getDataSource(String dataSourceName)
Queries the data source from a JNDI lookup. If the datasource is found and the data source is defined as managed, the service wraps the original DataSource instance in a new DataSource instance that is aware of its managed state. Otherwise it will return the original DataSource instance.
isManaged(String dataSourceName)
Indicates whether or not the given data source is managed.

A.8.3.2. Configuring DataSourceProvider

Configuration for DataSourceProvider is defined only if managed data sources are used. All data sources are considered not managed by default.
<configuration>
....  
   <component>
      <key>org.exoplatform.services.jdbc.DataSourceProvider</key>
      <type>org.exoplatform.services.jdbc.impl.DataSourceProviderImpl</type>
      <init-params>
         <!--  Indicates that the data source needs to check if a tx is active
              to decide if the provided connection needs to be managed or not.
              If it is set to false, the data source will provide only
              managed connections if the data source itself is managed.  -->
         <!--value-param>
            <name>check-tx-active</name>
            <value>true</value>
         </value-param-->
         <!-- Indicates that all the data sources are managed 
              If set to true the parameter never-managed and 
              managed-data-sources will be ignored -->
         <!--value-param>
            <name>always-managed</name>
            <value>true</value>
         </value-param-->
         <!-- Indicates the list of all the data sources that are 
              managed, each value tag can contain a list of
              data source names separated by a comma, in the
              example below we will register ds-foo1, ds-foo2 
              and ds-foo3 as managed data source. If always-managed
              and/or never-managed is set true this parameter is ignored -->
         <!--values-param>
            <name>managed-data-sources</name>
            <value>ds-foo1, ds-foo2</value>
            <value>ds-foo3</value>
         </values-param-->
      </init-params>
   </component>  
...
</configuration>

Field Descriptions

<check-tx-active>
Specifies the data source must check whether a transaction is active to determine if the provided connection must be managed or not. If it is set to false, the data source provides only managed connections if the data source itself is managed.
By default, this parameter is set to true. If set to true, the TransactionService is required in the configuration.
<always-managed>
Specifies all data sources are managed. If set to true, the parameters <never-managed> and <managed-data-sources> are ignored (marking all the data sources as managed). This parameter is set to false by default.
<managed-data-sources>
Specifies the list of all data sources that are managed. Each <value> element can contain a list of data source names separated by a comma. This parameter is ignored if <always-managed> and/or <never-managed> is set to true.

A.9. Configuring a portal container

A portal container is defined by several attributes:
Portal Container Name
The URL context to which the current portal is bound.
REST Context Name
The REST name used for access to portal application. Every portal has one unique REST context name.
Realm Name
The name of the security realm used for authentication when users log into the portal.
Dependencies
List of other web applications, whose resources are visible to the current portal (through the extension mechanism described later), and are searched for in the specified order.
<?xml version="1.0" encoding="UTF-8"?>
<configuration
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd
                       http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
   xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">

   <external-component-plugins>
      <!-- The full qualified name of the PortalContainerConfig -->
      <target-component>org.exoplatform.container.definition.PortalContainerConfig</target-component>

      <component-plugin>
         <!-- The name of the plugin -->
         <name>Add PortalContainer Definitions</name>

         <!-- The name of the method to call on the PortalContainerConfig
              in order to register the PortalContainerDefinitions -->
         <set-method>registerPlugin</set-method>

         <!-- The full qualified name of the PortalContainerDefinitionPlugin -->
         <type>org.exoplatform.container.definition.PortalContainerDefinitionPlugin</type>

         <init-params>
            <object-param>
               <name>portal</name>
               <object type="org.exoplatform.container.definition.PortalContainerDefinition">
                  <!-- The name of the portal container -->
                  <field name="name"><string>portal</string></field>

                  <!-- The name of the context name of the rest web application -->
                  <field name="restContextName"><string>rest</string></field>

                  <!-- The name of the realm -->
                  <field name="realmName"><string>exo-domain</string></field>

                  <!-- All the dependencies of the portal container ordered by loading priority -->
                  <field name="dependencies">
                     <collection type="java.util.ArrayList">
                        <value>
                           <string>eXoResources</string>
                        </value>
                        <value>
                           <string>portal</string>
                        </value>
                        <value>
                           <string>dashboard</string>
                        </value>
                        <value>
                           <string>exoadmin</string>
                        </value>
                        <value>
                           <string>eXoGadgets</string>
                        </value>
                        <value>
                           <string>eXoGadgetServer</string>
                        </value>
                        <value>
                           <string>rest</string>
                        </value>
                        <value>
                           <string>web</string>
                        </value>
                        <value>
                           <string>wsrp-producer</string>
                        </value>
                        <!-- The sample-ext has been added at the end of the dependency list
                             in order to have the highest priority -->
                        <value>
                           <string>sample-ext</string>
                        </value>
                     </collection>
                  </field>
               </object>
            </object-param>
         </init-params>
      </component-plugin>
   </external-component-plugins>
</configuration>
Dependencies are part of the extension mechanism. Every PortalContainer is represented by a PortalContainer instance, which contains the following configuration directives.

Portal Container Directives

eXoContainerContext
Contains information about the portal.
Unified Servlet Context
Controls web-archive-relative resource loading.
Unified Classloader
Classpath based resource loading.
Various methods for retrieving services
The Unified servlet context and unified classloader are part of the extension mechanism.
They provide the standard API (ServletContext, and ClassLoader) with specific resource loading behavior, such as visibility into associated web application archives, configured with the dependencies property of PortalContainerDefinition.
Resources from other web applications are queried in the order specified by the dependencies. The later entries in the list override the previous ones.

A.10. System property configuration

The property configuration service is designed to allow configuration of system properties from the in-line kernel configuration, or from specified property files.
The service is scoped at the root container level because it is used by all the services in the different portal containers in the application runtime.

System Property Definitions

properties
The properties init param takes a property declared to configure various properties.
<component>
  <key>PropertyManagerConfigurator</key>
  <type>org.exoplatform.container.PropertyConfigurator</type>
  <init-params>
    <properties-param>
      <name>properties</name>
      <property name="foo" value="bar"/>
    </properties-param>
  </init-params>
</component>
properties.url
The properties.url init param specifies an external file to load by URL reference. Both property and XML formats are supported (see the javadoc of the java.util.Properties class for more information).
When a property file is loaded the various property declarations are loaded in the order in which the properties are declared sequentially in the file.
<component>
  <key>PropertyManagerConfigurator</key>
  <type>org.exoplatform.container.PropertyConfigurator</type>
  <init-params>
    <value-param>
      <name>properties.url</name>
      <value>classpath:configuration.properties</value>
    </value-param>
  </init-params>
</component>
In the properties file corresponding to the external properties, existing variables can be reused to create a new variable. Using this feature, the prefix "portal.container." is not needed. For example:
my-var1=value 1
my-var2=value 2
complex-value=${my-var1}-${my-var2}
It is possible to replace the properties URL init param by a system property that overwrites it. The name of that property is exo.properties.url.
All variables can be defined through two possible syntaxes:
  • ${variable-name}, which does not define a default value. If the variable has not be set, the value is ${variable-name} to indicate that it could not be resolved.
  • ${variable-name:default-value}, which allows the default value to be defined after the semicolon. If the variable has not be set, the value will be the given default value.

A.10.1. Properties <init-param>

The properties init param takes a property declared to configure various properties.
<component>
  <key>PropertyManagerConfigurator</key>
  <type>org.exoplatform.container.PropertyConfigurator</type>
  <init-params>
    <properties-param>
      <name>properties</name>
      <property name="foo" value="bar"/>
    </properties-param>
  </init-params>
</component>

A.10.2. Properties URL <init-param>

The properties URL init param allow to load an external file by specifying its URL. Both property and XML format are supported, see the javadoc of the java.util.Properties class for more information. When a property file is loaded the various property declarations are loaded in the order in which the properties are declared sequentially in the file.
<component>
  <key>PropertyManagerConfigurator</key>
  <type>org.exoplatform.container.PropertyConfigurator</type>
  <init-params>
    <value-param>
      <name>properties.url</name>
      <value>classpath:configuration.properties</value>
    </value-param>
  </init-params>
</component>
In the properties file corresponding to the external properties, you can reuse variables before defining to create a new variable. In this case, the prefix "portal.container." is not needed, see an example below:
my-var1=value 1
my-var2=value 2
complex-value=${my-var1}-${my-var2}

A.10.3. System Property configuration of the properties URL

It is possible to replace the properties URL init param by a system property that overwrites it. The name of that property is exo.properties.url.

A.10.4. Variable Syntaxes

All the variables that we described in the previous sections can be defined through 2 possible syntaxes which are ${variable-name} or ${variable-name:default-value}. The first syntax doesn't define any default value so if the variable has not be set the value will be ${variable-name} to indicate that it could not be resolved. The second syntax allows you to define the default value after the semi colon so if the variable has not be set the value will be the given default value.

A.11. The Extension Mechanism and Portal Extensions

The Extension Mechanism makes it possible to override portal resources in a way similar to hardware plug-and-play functionality.
Customizations can be implemented without unpacking and repacking the original portal .war archives by adding a .war archive to the resources and configuring its position in the portal's classpath. Custom .war archives can be created with new resources that override the resources in the original archive.
These archives, packaged for use through the extension mechanism, are called portal extensions.

Procedure A.2. Creating a Portal Extension

  1. Declare the PortalConfigOwner servlet context listener in the web.xml of the web application.
    This example shows a portal extension called sample-ext.
    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE web-app PUBLIC -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN
         http://java.sun.com/dtd/web-app_2_3.dtd>
    <web-app>
    
       <display-name>sample-ext</display-name>
    
       <listener>
          <listener-class>org.exoplatform.container.web.PortalContainerConfigOwner</listener-class>
       </listener>
    
       ...
    
    </web-app>
    
  2. Add the application's servlet context name to the PortalContainerDefinition's list of dependencies. This must be done for each portal container that requires access to the new application.
    The application's position in these lists dictates its priority when the portal loads resources. The later the application appears in the list, the higher its resource priority will be.
  3. The new web archive is present on both the portal's unified classpath and unified servlet context resource path.

A.11.1. Running Multiple Portals

It is possible to run several independent portal containers, each bound to a different URL context, within the same JVM instance.
This method of deployment allows for efficient administration and resource consumption by allowing coexisting portals to reuse configuration arrangements through the extension mechanism.
Portals can inherit resources and configuration from existing web archives and add extra resources as needed, overriding those that need to be changed by including modified copies.
In order for a portal application to function correctly when deployed within a multiple portal deployment, it may have to dynamically query the information about the current portal container. The application must not make any assumptions about the name, and other information of the current portal, as there are now multiple different portals in play.
At any point during request processing, or life-cycle event processing, an application can retrieve this information through org.exoplatform.container.eXoContainerContext.
Sometimes an application must ensure that the proper PortalContainer is associated with the current eXoContainerContext call.
If the portal application contains servlets or servlet filters that need to access portal specific resources during their request processing, the servlet or filter must be associated with the current container.
A servlet in this instance must extend the org.exoplatform.container.web.AbstractHttpServlet class so as to properly initialize the current PortalContainer.
This will also set the current thread's context Classloader to one that looks for resources in associated web applications in the order specified by the dependencies configuration.
Filter classes need to extend the org.exoplatform.container.web.AbstractFilter.
Both AbstractHttpServlet, and AbstractFilter have a getContainer() method, which returns the current PortalContainer.
If your servlet handles the requests by implementing a service() method, that method must be renamed to match the following signature:
/**
 * Use this method instead of Servlet.service()
 */
protected void onService(ExoContainer container, HttpServletRequest req,
      HttpServletResponse res) throws ServletException, IOException;

Note

This ensures that AbstractHttpServlet's service() interception is not overwritten.
An application may also need access to portal information within the HttpSessionListener. Ensure the abstract class org.exoplatform.container.web.AbstractHttpSessionListener is extended.
In this instance, modify the method signatures as follows:
/**
 * Use this method instead of HttpSessionListener.sessionCreated()
 */
protected void onSessionCreated(ExoContainer container, HttpSessionEvent event);

/**
 * Use this method instead of HttpSessionListener.sessionDestroyed()
 */
protected void onSessionDestroyed(ExoContainer container, HttpSessionEvent event);
Another method must also be implemented in this case:
/**
 * Method should return true if unified servlet context,
 * and unified classloader should be made available
 */
protected boolean requirePortalEnvironment();
If this method returns true the current thread's context Classloader is set up according to the dependencies configuration and availability of the associated web applications.
If it returns false the standard application separation rules are used for resource loading (effectively turning off the extension mechanism).
This method exists on both AbstractHttpServlet and AbstractFilter. This is a default implementation that automatically returns true when it detects there is a current PortalContainer present and false otherwise.
ServletContextListener-based initialization access to PortalContainer
The portal has no direct control over the deployment of application archives (.war and .ear files); it is the application server that performs the deployment.
However, applications in the dependencies configuration must be deployed before the portal that depends on them is initialized in order for the extension mechanism to work properly.
Conversely, some applications may require an already initialized PortalContainer to properly initialize themselves. This gives rise to a recursive dependency problem.
A mechanism of initialization tasks and task queues has been implemented in the portal to resolve this dependency issue.
Web applications that depend on a current PortalContainer to initialize must avoid performing their initialization directly on a ServletContextListener executed during their deployment (before any PortalContainer was initialized).
To ensure this, a web application must package its initialization logic into an init task of an appropriate type and only use ServletContextListener to insert the init task instance into the proper init tasks queue.
An example of this is the Gadgets application which registers Google gadgets with the current PortalContainer. This example uses PortalContainerPostInitTask which is executed after the portal container has been initialized.
public class GadgetRegister implements ServletContextListener
{
   public void contextInitialized(ServletContextEvent event)
   {
      // Create a new post-init task
      final PortalContainerPostInitTask task = new PortalContainerPostInitTask() {

         public void execute(ServletContext context, PortalContainer portalContainer)
         {
            try
            {
               SourceStorage sourceStorage =
               (SourceStorage) portalContainer.getComponentInstanceOfType(SourceStorage.class);
               ...
            }
            catch (RuntimeException e)
            {
               throw e;
            }
            catch (Exception e)
            {
               throw new RuntimeException("Initialization failed: ", e);
            }
         }
      };

      // Add post-init task for execution on all the portal containers
      // that depend on the given ServletContext according to 
      // PortalContainerDefinitions (via Dependencies configuration)
      PortalContainer.addInitTask(event.getServletContext(), task);
   }
}
In some situations initialization may be required after the portal container is instantiated but before it has initialized. PortalContainerPreInitTask can be used in that case.
Use PortalContainerPostCreateTask if initialization is required after all the post-init tasks have been executed.
LoginModules
If some custom LoginModules require the current eXoContainer for initialization ensure they extend org.exoplatform.services.security.jaas.AbstractLoginModule.
AbstractLoginModule enforces some basic configuration. It recognizes two initialization options; portalContainerName and realmName.
The values for these options can be accessed through protected fields of the same name.

A.12. Manageability

A.12.1. Introduction

The kernel has a framework for exposing a management view of the various sub systems of the platform.
The management view is a portal-specific term that means defining how we can access relevant information about the system and how we can apply management operations.
JMX is the default standard for exposing a management view in the Java Platform, but we take in consideration other kind of views such as REST web services. Therefore, the framework is not tied to JMX, yet it provides a JMX part to define more precisely details related to the JMX management view.
The legacy framework is still in use but is deprecated in favor of the new framework, as it is less tested and less efficient.

A.12.2. Managed framework API

The managed frameworks define an API for exposing a management view of objects. The API is targeted for internal use and is not a public API. The framework leverages Java 5 annotations to describe the management view from an object.

A.12.2.1. Annotations

The following annotations are available for use in the eXo Kernel.

Annotations List

@org.exoplatform.management.annotations.Managed annotation
The @Managed annotates elements that wants to expose a management view to a management layer.
  • The @Managed annotation on objects exports a management view for the objects annotated.
  • The @Managed annotation on getters and setters defines a managed property. An annotated getter defines a read property, an annotated setter defines a write property. If a matching getter or setter is annotated, the annotation defines a read-write property.
  • The @Managed annotation on methods defines a managed operation.
@org.exoplatform.management.annotations.ManagedDescription
The @ManagedDescription annotation provides a description of a managed element. It is valid to annotated object or methods. It takes as sole argument a string that is the description value.
@org.exoplatform.management.annotations.ManagedName
The @ManagedName annotation provides an alternative name for managed properties. It is used to accomodate legacy methods of an object that can be renamed for compatibility reasons. It takes as sole argument a string that is the name value.
@org.exoplatform.management.annotations.ManagedBy
The @ManagedBy annotation defines a delegate class for exposing a management view. The sole argument of the annotation are class literals. The delegate class must provide a constructor with the managed object as argument.
A.12.2.1.1. @org.exoplatform.management.annotations.Managed annotation
The @Managed annotates elements that wants to expose a management view to a management layer.
@Managed for objects
The framework will export a management view for the objects annotated.
@Managed for getter/setter
Defines a managed property. An annotated getter defines a read property, an annotated setter defines a write property and if matching getter/setter are annotated it defines a read/write property.
@Managed on method
Defines a managed operation.
A.12.2.1.2. @org.exoplatform.management.annotations.ManagedDescription
The @ManagedDescription annotation provides a description of a managed element. It is valid to annotated object or methods. It takes as sole argument a string that is the description value.
A.12.2.1.3. @org.exoplatform.management.annotations.ManagedName
The @ManagedName annotation provides an alternative name for managed properties. It is used to accomodate legacy methods of an object that can be renamed for compatibility reasons. It takes as sole argument a string that is the name value.
A.12.2.1.4. @org.exoplatform.management.annotations.ManagedBy
The @ManagedBy annotation defines a delegate class for exposing a management view. The sole argument of the annotation are class literals. The delegate class must provide a constructor with the managed object as argument.

A.12.3. JMX Management View

A.12.3.1. JMX Annotations

The following JMX annotations are available for use in eXo Kernel.

JMX Annotations

@org.exoplatform.management.jmx.annotations.Property
The @Property annotation is used to within other annotations such as @NameTemplate or @NamingContext. It should be seen as a structural way for a list of properties. A property is made of a key and a value. The value can either be a string literal or it can be surrounded by curly braces ({}) to a dynamic property. A dynamic property is resolved against the instance of the object at runtime.
@org.exoplatform.management.jmx.annotations.NameTemplate
The @NameTemplate defines a template used at registration time of a managed object to create the JMX object name. The template is populated with properties.
@NameTemplate({
  @Property(key="container", value="workspace"),
  @Property(key="name", value="{Name}")})
@org.exoplatform.management.jmx.annotations.NamingContext
The @NamingContext annotation defines a set of properties which are used within a management context. It allows to propagate properties down to managed objects which are defined by an object implementing the ManagementAware interface. The goal is to scope different instances of the same class that would have the same object name otherwise.
@NamingContext(@Property(key="workspace", value="{Name}"))
A.12.3.1.1. @org.exoplatform.management.jmx.annotations.Property annotation
The @Property annotation is used to within other annotations such as @NameTemplate or @NamingContext. It should be seen as a structural way for a list of properties. A property is made of a key and a value. The value can either be a string literal or it can be surrounded by curly brace to be a dynamic property. A dynamic property is resolved against the instance of the object at runtime.
A.12.3.1.2. @org.exoplatform.management.jmx.annotations.NameTemplate annotation
The @NameTemplate defines a template that is used at registration time of a managed object to create the JMX object name. The template is formed of properties.
@NameTemplate({
  @Property(key="container", value="workspace"),
  @Property(key="name", value="{Name}")})
A.12.3.1.3. @org.exoplatform.management.jmx.annotations.NamingContext annotation
The @NamingContext annotation defines a set of properties which are used within a management context. It allows to propagate properties down to managed objects which are defined by an object implementing the ManagementAware interface. The goal is to scope different instances of the same class that would have the same object name otherwise.
@NamingContext(@Property(key="workspace", value="{Name}"))

A.12.4. Example

A.12.4.1. CacheService example

The cache service delegates most of the work to the CacheServiceManaged class by using the @ManagedBy annotation. At runtime when a new cache is created, it calls the CacheServiceManaged class in order to let the CacheServiceManaged object register the cache.
@ManagedBy(CacheServiceManaged.class)
public class CacheServiceImpl implements CacheService {

  CacheServiceManaged managed;
  ...
  synchronized private ExoCache createCacheInstance(String region) throws Exception {
    ...
    if (managed != null) {
      managed.registerCache(simple);
    }
    ...
  }
}
The ExoCache interface is annotated to define its management view. The @NameTemplate is used to produce object name values when ExoCache instance are registered.
@Managed
@NameTemplate({@Property(key="service", value="cache"), @Property(key="name", value="{Name}")})
@ManagedDescription("Exo Cache")
public interface ExoCache {

  @Managed
  @ManagedName("Name")
  @ManagedDescription("The cache name")
  public String getName();

  @Managed
  @ManagedName("Capacity")
  @ManagedDescription("The maximum capacity")
  public int getMaxSize();

  @Managed
  @ManagedDescription("Evict all entries of the cache")
  public void clearCache() throws Exception;

  ...
}
The CacheServiceManaged is the glue code between the CacheService and the management view. The main reason is that only exo services are registered automatically against the management view. Any other managed bean must be registered manually for now. Therefore, it needs to know about the management layer via the management context. The management context allows an object implementing the ManagementAware interface to receive a context to perform further registration of managed objects.
@Managed
public class CacheServiceManaged implements ManagementAware {

  /** . */
  private ManagementContext context;

  /** . */
  private CacheServiceImpl cacheService;

  public CacheServiceManaged(CacheServiceImpl cacheService) {
    this.cacheService = cacheService;

    //
    cacheService.managed = this;
  }

  public void setContext(ManagementContext context) {
    this.context = context;
  }

  void registerCache(ExoCache cache) {
    if (context != null) {
      context.register(cache);
    }
  }
}