JBoss.orgCommunity Documentation

eXoJCR Reference Manual

Java Content Repository and Extension services


I. eXoJCR
1. Introduction in eXoJCR
1.1. JCR (JSR-170) API main concepts
1.1.1. Data model
2. Basic concepts of eXoJCR
3. eXo JCR configuration
3.1. Related documents
3.2. Portal and Standalone configuration
3.2.1. JCR Configuration
3.2.2. Repository service configuration
4. JDBC Data Container Config
4.1. Introduction
4.2. Multi-database Configuration
4.3. Single-database configuration
4.3.1. Configuration without DataSource
4.3.2. Dynamic Workspace Creation
4.4. Simple and Complex queries
4.5. Forse Query Hints
4.6. Notes for Microsoft Windows users
5. External Value Storages
5.1. Introduction
5.2. Tree File Value Storage
5.3. Simple File Value Storage
5.4. Content Addressable Value storage (CAS) support
6. Search Configuration
6.1. XML Configuration
6.2. Configuration parameters
6.3. Global Search Index
6.3.1. Global Search Index Configuration
6.3.2. Customized Search Indexes and Analyzers
6.4. Index Adjustments
6.4.1. IndexingConfiguration
6.4.2. Index rules
6.4.3. Index Aggregates
6.4.4. Property-Level Analyzers
7. Multilanguage support in eXo JCR RDB backend
7.1. Intro
7.2. Oracle
7.3. DB2
7.4. MySQL
7.5. PostgreSQL
8. JCR Configuration persister
8.1. Idea
8.2. Usage
9. Configuring JBoss AS with eXo JCR in cluster
9.1. Launching Cluster
9.1.1. Deploying eXo JCR to JBoss As
9.1.2. Configuring JCR to use external configuration
9.2. Requirements
9.2.1. Enviorenment requirements
9.2.2. Enviorenment requirements
10. JBoss Cache configuration
10.1. JBoss cache configuration for indexer, lock manager and data container
10.2. JGroups configuration
10.3. Shipped JBoss Cache configuration templates
10.3.1. Data container template
10.3.2. Lock manager template
10.3.3. Query handler (indexer) template
11. LockManager configuration
11.1. Introduction
11.2. LockManagerImpl
11.3. CacheableLockManagerImpl
11.3.1. Configuration
11.3.2. Simple JbossCache Configuraion
11.3.3. Template JBossCache Configuration
11.3.4. Data Types in Different Databases
12. QueryHandler configuration
12.1. How does it work?
12.2. Configuration
12.2.1. Common requirements
12.2.2. Query-handler configuration
12.2.3. JBoss-Cache template configuration
13. JBossTransactionsService
13.1. Introduction
13.2. Configuration
14. TransactionManagerLookup
14.1. Configuration
15. eXo JCR statistics
15.1. Statistics on the Database Access Layer
15.2. Statistics on the JCR API accesses
15.3. Statistics Manager
II. eXoKernel
16. eXo Kernel
16.1. eXo Kernel introduction
17. Configuration
17.1. Kernel configuration namespace
17.2. Understanding How configuration files are loaded
17.2.1. Configuration Retrieval
17.2.2. Advanced concepts for the PortalContainers
17.3. System property configuration
17.3.1. Properties init param
17.3.2. Properties URL init param
17.3.3. System Property configuration of the properties URL
17.4. Runtime configuration profiles
17.4.1. Profiles activation
17.4.2. Profiles configuration
17.5. Component request life cycle
17.5.1. Component request life cycle contract
17.5.2. Request life cycle
17.5.3. When request life cycle is triggered
18. eXo Cache
18.1. Basic concepts
18.2. eXo Cache extension
18.3. eXo Cache based on JBoss Cache
18.3.1. Configure the ExoCacheFactory
18.3.2. Add specific configuration for a cache
18.3.3. Add a cache creator
18.3.4. Define a cache
19. TransactionService
19.1. Base information
20. JNDI naming
20.1. Prerequisites
20.2. How it works
20.2.1. JNDI System property initialization
20.2.2. JNDI reference binding
20.3. Configuration examples
20.4. Recommendations for Application Developers
20.5. InitialContextInitializer API
21. Logs configuration
21.1. Introdution
21.2. Logs configuration initializer
21.3. Configuration examples
21.3.1. Log4J
21.3.2. JDK Logging
21.3.3. Commons Logging SimpleLog
21.4. Tips and Troubleshooting
21.4.1. JBoss tips
21.4.2. Other tips
III. eXoCore
22. eXo Core
22.1. eXo Core introduction
23. Database Creator
23.1. About
23.2. API
23.3. A configuration examples
23.4. An examples of a DDL script
IV. eXoWS
24. eXo Web Services
24.1. eXo Web Services introduction

Table of Contents

1. Introduction in eXoJCR
1.1. JCR (JSR-170) API main concepts
1.1.1. Data model
2. Basic concepts of eXoJCR
3. eXo JCR configuration
3.1. Related documents
3.2. Portal and Standalone configuration
3.2.1. JCR Configuration
3.2.2. Repository service configuration
4. JDBC Data Container Config
4.1. Introduction
4.2. Multi-database Configuration
4.3. Single-database configuration
4.3.1. Configuration without DataSource
4.3.2. Dynamic Workspace Creation
4.4. Simple and Complex queries
4.5. Forse Query Hints
4.6. Notes for Microsoft Windows users
5. External Value Storages
5.1. Introduction
5.2. Tree File Value Storage
5.3. Simple File Value Storage
5.4. Content Addressable Value storage (CAS) support
6. Search Configuration
6.1. XML Configuration
6.2. Configuration parameters
6.3. Global Search Index
6.3.1. Global Search Index Configuration
6.3.2. Customized Search Indexes and Analyzers
6.4. Index Adjustments
6.4.1. IndexingConfiguration
6.4.2. Index rules
6.4.3. Index Aggregates
6.4.4. Property-Level Analyzers
7. Multilanguage support in eXo JCR RDB backend
7.1. Intro
7.2. Oracle
7.3. DB2
7.4. MySQL
7.5. PostgreSQL
8. JCR Configuration persister
8.1. Idea
8.2. Usage
9. Configuring JBoss AS with eXo JCR in cluster
9.1. Launching Cluster
9.1.1. Deploying eXo JCR to JBoss As
9.1.2. Configuring JCR to use external configuration
9.2. Requirements
9.2.1. Enviorenment requirements
9.2.2. Enviorenment requirements
10. JBoss Cache configuration
10.1. JBoss cache configuration for indexer, lock manager and data container
10.2. JGroups configuration
10.3. Shipped JBoss Cache configuration templates
10.3.1. Data container template
10.3.2. Lock manager template
10.3.3. Query handler (indexer) template
11. LockManager configuration
11.1. Introduction
11.2. LockManagerImpl
11.3. CacheableLockManagerImpl
11.3.1. Configuration
11.3.2. Simple JbossCache Configuraion
11.3.3. Template JBossCache Configuration
11.3.4. Data Types in Different Databases
12. QueryHandler configuration
12.1. How does it work?
12.2. Configuration
12.2.1. Common requirements
12.2.2. Query-handler configuration
12.2.3. JBoss-Cache template configuration
13. JBossTransactionsService
13.1. Introduction
13.2. Configuration
14. TransactionManagerLookup
14.1. Configuration
15. eXo JCR statistics
15.1. Statistics on the Database Access Layer
15.2. Statistics on the JCR API accesses
15.3. Statistics Manager

Like other eXo services eXo JCR can be configured and used in portal or embedded mode (as a service embedded in eXo Portal) and in standalone mode.

In Embedded mode, JCR services are registered in the Portal container and the second option is to use a Standalone container. The main difference between these container types is that the first one is intended to be used in a Portal (Web) environment, while the second one can be used standalone (TODO see the comprehensive page Service Configuration for Beginners for more details).

The following setup procedure is used to obtain a Standalone configuration (TODO find more in Container configuration):

JCR service configuration looks like:

<component>
    <key>org.exoplatform.services.jcr.RepositoryService</key>
    <type>org.exoplatform.services.jcr.impl.RepositoryServiceImpl</type>
  </component>
  <component>
    <key>org.exoplatform.services.jcr.config.RepositoryServiceConfiguration</key>
    <type>org.exoplatform.services.jcr.impl.config.RepositoryServiceConfigurationImpl</type>
    <init-params>
      <value-param>
        <name>conf-path</name>
        <description>JCR repositories configuration file</description>
        <value>jar:/conf/standalone/exo-jcr-config.xml</value>
      </value-param>
      <properties-param>
        <name>working-conf</name>
        <description>working-conf</description>
        <property name="source-name" value="jdbcjcr" />
        <property name="dialect" value="hsqldb" />
        <property name="persister-class-name" value="org.exoplatform.services.jcr.impl.config.JDBCConfigurationPersister" />
      </properties-param>
    </init-params>
  </component>

conf-path : a path to a RepositoryService JCR Configuration

working-conf : optional; JCR configuration persister configuration. If there isn't a working-conf the persister will be disabled

Default configuration of the Repository Service located in jar:/conf/portal/exo-jcr-config.xml, it will be available for portal and standalone modes.

In portal mode it is overriden and located in the portal web application portal/WEB-INF/conf/jcr/repository-configuration.xml.

Example of Repository Service configuration for standalone mode:

<repository-service default-repository="repository">
   <repositories>
      <repository name="db1" system-workspace="ws" default-workspace="ws">
         <security-domain>exo-domain</security-domain>
         <access-control>optional</access-control>
         <session-max-age>1h</session-max-age>
         <authentication-policy>org.exoplatform.services.jcr.impl.core.access.JAASAuthenticator</authentication-policy>
         <workspaces>
            <workspace name="production">
               <!-- for system storage -->
               <container class="org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer">
                  <properties>
                     <property name="source-name" value="jdbcjcr" />
                     <property name="multi-db" value="false" />
                     <property name="update-storage" value="false" />
                     <property name="max-buffer-size" value="200k" />
                     <property name="swap-directory" value="../temp/swap/production" />
                  </properties>
                  <value-storages>
                     <value-storage id="system" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage">
                        <properties>
                           <property name="path" value="../temp/values/production" />
                        </properties>
                        <filters>
                           <filter property-type="Binary" />
                        </filters>
                     </value-storage>
                  </value-storages>
               </container>
               <initializer class="org.exoplatform.services.jcr.impl.core.ScratchWorkspaceInitializer">
                  <properties>
                     <property name="root-nodetype" value="nt:unstructured" />
                  </properties>
               </initializer>
               <cache enabled="true" class="org.exoplatform.services.jcr.impl.dataflow.persistent.LinkedWorkspaceStorageCacheImpl">
                  <properties>
                     <property name="max-size" value="10k" />
                     <property name="live-time" value="1h" />
                  </properties>
               </cache>
               <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
                  <properties>
                     <property name="index-dir" value="../temp/jcrlucenedb/production" />
                  </properties>
               </query-handler>
               <lock-manager>
                  <time-out>15m</time-out>
                  <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister">
                     <properties>
                        <property name="path" value="../temp/lock/system" />
                     </properties>
                  </persister>
               </lock-manager>
            </workspace>

            <workspace name="backup">
               <container class="org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer">
                  <properties>
                     <property name="source-name" value="jdbcjcr" />
                     <property name="multi-db" value="false" />
                     <property name="update-storage" value="false" />
                     <property name="max-buffer-size" value="200k" />
                     <property name="swap-directory" value="../temp/swap/backup" />
                  </properties>
                  <value-storages>
                     <value-storage id="draft" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage">
                        <properties>
                           <property name="path" value="../temp/values/backup" />
                        </properties>
                        <filters>
                           <filter property-type="Binary" />
                        </filters>
                     </value-storage>
                  </value-storages>
               </container>
               <initializer class="org.exoplatform.services.jcr.impl.core.ScratchWorkspaceInitializer">
                  <properties>
                     <property name="root-nodetype" value="nt:unstructured" />
                  </properties>
               </initializer>
               <cache enabled="true" class="org.exoplatform.services.jcr.impl.dataflow.persistent.LinkedWorkspaceStorageCacheImpl">
                  <properties>
                     <property name="max-size" value="10k" />
                     <property name="live-time" value="1h" />
                  </properties>
               </cache>
               <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
                  <properties>
                     <property name="index-dir" value="../temp/jcrlucenedb/backup" />
                  </properties>
               </query-handler>
            </workspace>
          </workspaces>
       </repository>
   </repositories>
</repository-service>

Repository Service configuration:

default-repository - the name of a default repository (one returned by RepositoryService.getRepository())

repositories - the list of repositories

Repository configuration:

name - the name of a repository

default-workspace - the name of a workspace obtained using Session's login() or login(Credentials) methods (ones without an explicit workspace name)

system-workspace - name of workspace where /jcr:system node is placed

security-domain - the name of a security domain for JAAS authentication

access-control - the name of an access control policy. There can be 3 types: optional - ACL is created on-demand(default), disable - no access control, mandatory - an ACL is created for each added node(not supported yet)

authentication-policy - the name of an authentication policy class

workspaces - the list of workspaces

session-max-age - the time after which an idle session will be removed (called logout). If not set, the idle session will never be removed.

Workspace configuration:

name - the name of a workspace

auto-init-root-nodetype - DEPRECATED in JCR 1.9 (use initializer). The node type for root node initialization

container - workspace data container (physical storage) configuration

initializer - workspace initializer configuration

cache - workspace storage cache configuration

query-handler - query handler configuration

Workspace data container configuration:

class - A workspace data container class name

properties - the list of properties (name-value pairs) for the concrete Workspace data container

value-storages - the list of value storage plugins

Value Storage plugin configuration (optional feature):

value-storage - Optional value Storage plugin definition

class- a value storage plugin class name (attribute)

properties - the list of properties (name-value pairs) for a concrete Value Storage plugin

filters - the list of filters defining conditions when this plugin is applicable

Initializer configuration (optional):

class - initializer implementation class.

properties - the list of properties (name-value pairs). Properties are supported:

root-nodetype - The node type for root node initialization

root-permissions - Default permissions of the root node. It is defined as a set of semicolon-delimited permissions containing a group of space-delimited identities (user, group etc, see Organization service documentation for details) and the type of permission. For example any read;:/admin read;:/admin add_node;:/admin set_property;:/admin remove means that users from group admin have all permissions and other users have only a 'read' permission.

Configurable initializer adds a capability to override workspace initial startup procedure.

Cache configuration:

enabled - if workspace cache is enabled

class - cache implementation class, optional from 1.9. Default value is org.exoplatform.services.jcr.impl.dataflow.persistent.LinkedWorkspaceStorageCacheImpl.

Cache can be configured to use concrete implementation of WorkspaceStorageCache interface. JCR core has two implementation to use: * LinkedWorkspaceStorageCacheImpl - default, with configurable read behavior and statistic. * WorkspaceStorageCacheImpl - pre 1.9, still can be used.

properties - the list of properties (name-value pairs) for Workspace cache:

max-size - cache maximum size.

live-time - cached item live time.

LinkedWorkspaceStorageCacheImpl supports additional optional parameters TODO

Query Handler configuration:

class - A Query Handler class name

properties - the list of properties (name-value pairs) for a Query Handler (indexDir) properties and advanced features described in *Search Configuration*

Lock Manager configuration:

time-out - time after which the unused global lock will be removed.

persister - a class for storing lock information for future use. For example, remove lock after jcr restart.

path - a lock folder, each workspace has its own.

Configuration definition:

<!ELEMENT repository-service (repositories)>
  <!ATTLIST repository-service default-repository NMTOKEN #REQUIRED>
  <!ELEMENT repositories (repository)>
  <!ELEMENT repository (security-domain,access-control,session-max-age,authentication-policy,workspaces)>
  <!ATTLIST repository
	default-workspace NMTOKEN #REQUIRED
	name NMTOKEN #REQUIRED
	system-workspace NMTOKEN #REQUIRED
  >
  <!ELEMENT security-domain (#PCDATA)>
  <!ELEMENT access-control (#PCDATA)>
  <!ELEMENT session-max-age (#PCDATA)>
  <!ELEMENT authentication-policy (#PCDATA)>
  <!ELEMENT workspaces (workspace+)>
  <!ELEMENT workspace (container,initializer,cache,query-handler)>
  <!ATTLIST workspace name NMTOKEN #REQUIRED>
  <!ELEMENT container (properties,value-storages)>
  <!ATTLIST container class NMTOKEN #REQUIRED>
  <!ELEMENT value-storages (value-storage+)>
  <!ELEMENT value-storage (properties,filters)>
  <!ATTLIST value-storage class NMTOKEN #REQUIRED>
  <!ELEMENT filters (filter+)>
  <!ELEMENT filter EMPTY>
  <!ATTLIST filter property-type NMTOKEN #REQUIRED>
  <!ELEMENT initializer (properties)>
  <!ATTLIST initializer class NMTOKEN #REQUIRED>
  <!ELEMENT cache (properties)>
  <!ATTLIST cache 
        enabled NMTOKEN #REQUIRED
        class NMTOKEN #REQUIRED
  >
  <!ELEMENT query-handler (properties)>
  <!ATTLIST query-handler class NMTOKEN #REQUIRED>
  <!ELEMENT access-manager (properties)>
  <!ATTLIST access-manager class NMTOKEN #REQUIRED>
  <!ELEMENT lock-manager (time-out,persister)>
  <!ELEMENT time-out (#PCDATA)>
  <!ELEMENT persister (properties)>
  <!ELEMENT properties (property+)>
  <!ELEMENT property EMPTY>

eXo JCR persistent data container can work in two configuration modes:

The data container uses the JDBC driver to communicate with the actual database software, i.e. any JDBC-enabled data storage can be used with eXo JCR implementation.

Currently the data container is tested with the following RDBMS:

Each database software supports ANSI SQL standards but has its own specifics too. So, each database has its own configuration in eXo JCR as a database dialect parameter. If you need a more detailed configuration of the database it's possible to do that by editing the metadata SQL-script files.

In case the non-ANSI node name is used it's necessary to use a database with MultiLanguage support[TODO link to MultiLanguage]. Some JDBC drivers need additional parameters for establishing a Unicode friendly connection. E.g. under mysql it's necessary to add an additional parameter for the JDBC driver at the end of JDBC URL. For instance: jdbc:mysql://exoua.dnsalias.net/portal?characterEncoding=utf8

There are preconfigured configuration files for HSQLDB. Look for these files in /conf/portal and /conf/standalone folders of the jar-file exo.jcr.component.core-XXX.XXX.jar or source-distribution of eXo JCR implementation.

By default the configuration files are located in service jars /conf/portal/configuration.xml (eXo services including JCR Repository Service) and exo-jcr-config.xml (repositories configuration). In eXo portal product JCR is configured in portal web application portal/WEB-INF/conf/jcr/jcr-configuration.xml (JCR Repository Service and related serivces) and repository-configuration.xml (repositories configuration).

Read more about Repository configuration.

You need to configure each workspace in a repository. You may have each one on different remote servers as far as you need.

First of all configure the data containers in the org.exoplatform.services.naming.InitialContextInitializer service. It's the JNDI context initializer which registers (binds) naming resources (DataSources) for data containers.

Example (standalone mode, two data containers jdbcjcr - local HSQLDB, jdbcjcr1 - remote MySQL):

<component>
    <key>org.exoplatform.services.naming.InitialContextInitializer</key>
    <type>org.exoplatform.services.naming.InitialContextInitializer</type>
    <component-plugins>
      <component-plugin>
        <name>bind.datasource</name>
        <set-method>addPlugin</set-method>
        <type>org.exoplatform.services.naming.BindReferencePlugin</type>
        <init-params>
          <value-param>
            <name>bind-name</name>
            <value>jdbcjcr</value>
          </value-param>
          <value-param>
            <name>class-name</name>
            <value>javax.sql.DataSource</value>
          </value-param>
          <value-param>
            <name>factory</name>
            <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
          </value-param>
          <properties-param>
            <name>ref-addresses</name>
            <description>ref-addresses</description>
            <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
            <property name="url" value="jdbc:hsqldb:file:target/temp/data/portal"/>
            <property name="username" value="sa"/>
            <property name="password" value=""/>
          </properties-param>
        </init-params>
      </component-plugin>
      <component-plugin>
        <name>bind.datasource</name>
        <set-method>addPlugin</set-method>
        <type>org.exoplatform.services.naming.BindReferencePlugin</type>
        <init-params>
          <value-param>
            <name>bind-name</name>
            <value>jdbcjcr1</value>
          </value-param>
          <value-param>
            <name>class-name</name>
            <value>javax.sql.DataSource</value>
          </value-param>
          <value-param>
            <name>factory</name>
            <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
          </value-param>
          <properties-param>
            <name>ref-addresses</name>
            <description>ref-addresses</description>
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://exoua.dnsalias.net/jcr"/>
            <property name="username" value="exoadmin"/>
            <property name="password" value="exo12321"/>
            <property name="maxActive" value="50"/>
            <property name="maxIdle" value="5"/>
            <property name="initialSize" value="5"/>
          </properties-param>
        </init-params>
      </component-plugin>
    <component-plugins>
    <init-params>
      <value-param>
        <name>default-context-factory</name>
        <value>org.exoplatform.services.naming.SimpleContextFactory</value>
      </value-param>
    </init-params>
  </component>

We configure the database connection parameters:

There can be connection pool configuration parameters (org.apache.commons.dbcp.BasicDataSourceFactory):

When the data container configuration is done we can configure the repository service. Each workspace will be configured for its own data container.

Example (two workspaces ws - jdbcjcr, ws1 - jdbcjcr1):

<workspaces>
  <workspace name="ws" auto-init-root-nodetype="nt:unstructured">
    <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
    <properties>
      <property name="source-name" value="jdbcjcr"/>
      <property name="dialect" value="hsqldb"/>
      <property name="multi-db" value="true"/>
      <property name="max-buffer-size" value="200K"/>
      <property name="swap-directory" value="target/temp/swap/ws"/>   
    </properties>
    </container>
    <cache enabled="true">
      <properties>
        <property name="max-size" value="10K"/><!-- 10Kbytes -->
        <property name="live-time" value="30m"/><!-- 30 min -->
      </properties>
    </cache>
    <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
    <properties>
      <property name="index-dir" value="target/temp/index"/>
    </properties>
    </query-handler>
    <lock-manager>
    <time-out>15m</time-out><!-- 15 min -->
    <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister">
      <properties>
      <property name="path" value="target/temp/lock/ws"/>
      </properties>
    </persister>
    </lock-manager>
  </workspace>
  <workspace name="ws1" auto-init-root-nodetype="nt:unstructured">
    <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
    <properties>
      <property name="source-name" value="jdbcjcr1"/>
      <property name="dialect" value="mysql"/>
      <property name="multi-db" value="true"/>
      <property name="max-buffer-size" value="200K"/>
      <property name="swap-directory" value="target/temp/swap/ws1"/>   
    </properties>
    </container>
    <cache enabled="true">
      <properties>
        <property name="max-size" value="10K"/>
        <property name="live-time" value="5m"/>
      </properties>
    </cache>
    <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
    <properties>
      <property name="index-dir" value="target/temp/index"/>
    </properties>
    </query-handler>
    <lock-manager>
    <time-out>15m</time-out><!-- 15 min -->
    <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister">
      <properties>
      <property name="path" value="target/temp/lock/ws1"/>
      </properties>
    </persister>
    </lock-manager>
  </workspace>
</workspaces>
  • source-name - a javax.sql.DataSource name configured in InitialContextInitializer component (was sourceName prior JCR 1.9);

  • dialect - a database dialect, one of "hsqldb", "mysql", "mysql-utf8", "pgsql", "oracle", "oracle-oci", "mssql", "sybase", "derby", "db2", "db2v8" or "auto" for dialect autodetection;

  • multi-db - enable multi-database container with this parameter (set value "true");

  • max-buffer-size - a threshold (in bytes) after which a javax.jcr.Value content will be swapped to a file in a temporary storage. I.e. swap for pending changes.

  • swap-directory - a path in the file system used to swap the pending changes.

In this way we have configured two workspace which will be persisted in two different databases (ws in HSQLDB, ws1 in MySQL).

Note

Starting from v.1.9 repository configuration parameters supports human-readable formats of values (e.g. 200K - 200 Kbytes, 30m - 30 minutes etc)

It's more simple to configure a single-database data container. We have to configure one naming resource.

Example (embedded mode for jdbcjcr data container):

<external-component-plugins>
    <target-component>org.exoplatform.services.naming.InitialContextInitializer</target-component>
    <component-plugin>
        <name>bind.datasource</name>
        <set-method>addPlugin</set-method>
        <type>org.exoplatform.services.naming.BindReferencePlugin</type>
        <init-params>
          <value-param>
            <name>bind-name</name>
            <value>jdbcjcr</value>
          </value-param>
          <value-param>
            <name>class-name</name>
            <value>javax.sql.DataSource</value>
          </value-param>
          <value-param>
            <name>factory</name>
            <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
          </value-param>
          <properties-param>
            <name>ref-addresses</name>
            <description>ref-addresses</description>
            <property name="driverClassName" value="org.postgresql.Driver"/>
            <property name="url" value="jdbc:postgresql://exoua.dnsalias.net/portal"/>
            <property name="username" value="exoadmin"/>
            <property name="password" value="exo12321"/>
            <property name="maxActive" value="50"/>
            <property name="maxIdle" value="5"/>
            <property name="initialSize" value="5"/>
          </properties-param>
        </init-params>
    </component-plugin>
  </external-component-plugins>

And configure repository workspaces in repositories configuration with this one database. Parameter "multi-db" must be switched off (set value "false").

Example (two workspaces ws - jdbcjcr, ws1 - jdbcjcr):

<workspaces>
  <workspace name="ws" auto-init-root-nodetype="nt:unstructured">
    <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
    <properties>
      <property name="source-name" value="jdbcjcr"/>
      <property name="dialect" value="pgsql"/>
      <property name="multi-db" value="false"/>
      <property name="max-buffer-size" value="200K"/>
      <property name="swap-directory" value="target/temp/swap/ws"/>
    </properties>
    </container>
    <cache enabled="true">
    <properties>
      <property name="max-size" value="10K"/>
      <property name="live-time" value="30m"/>
    </properties>
    </cache>
    <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
    <properties>
      <property name="index-dir" value="../temp/index"/>
    </properties>
    </query-handler>
    <lock-manager>
    <time-out>15m</time-out>
    <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister">
      <properties>
      <property name="path" value="target/temp/lock/ws"/>
      </properties>
    </persister>
    </lock-manager>
  </workspace>
  <workspace name="ws1" auto-init-root-nodetype="nt:unstructured">
    <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
    <properties>
      <property name="source-name" value="jdbcjcr"/>
      <property name="dialect" value="pgsql"/>
      <property name="multi-db" value="false"/>
      <property name="max-buffer-size" value="200K"/>
      <property name="swap-directory" value="target/temp/swap/ws1"/>
    </properties>
    </container>
    <cache enabled="true">
    <properties>
      <property name="max-size" value="10K"/>
      <property name="live-time" value="5m"/>
    </properties>
    </cache>
    <lock-manager>
    <time-out>15m</time-out>
    <persister class="org.exoplatform.services.jcr.impl.core.lock.FileSystemLockPersister">
      <properties>
      <property name="path" value="target/temp/lock/ws1"/>
      </properties>
    </persister>
    </lock-manager>
  </workspace>
</workspaces>

In this way we have configured two workspaces which will be persisted in one database (PostgreSQL).

Holds Values in tree-like FileSystem files. path property points to the root directory to store the files.

This is a recommended type of external storage, it can contain large amount of files limited only by disk/volume free space.

A disadvantage it's a higher time on Value deletion due to unused tree-nodes remove.

<value-storage id="Storage #1" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage">
     <properties>
       <property name="path" value="data/values"/>
     </properties>
     <filters>
       <filter property-type="Binary" min-value-size="1M"/>
     </filters>

Where :

id - the value storage unique identifier, used for linking with properties stored in workspace container
path - a location where value files will be stored

Each file value storage can have the filter(s) for incoming values. A filter can match values by property type (property-type), property name (property-name), ancestor path (ancestor-path) and/or size of values stored (min-value-size, in bytes). In code sample we use a filter with property-type and min-value-size only. I.e. storage for binary values with size greater of 1MB. It's recommended to store properties with large values in file value storage only.

Another example shows a value storage with different locations for large files (min-value-size a 20Mb-sized filter). A value storage uses ORed logic in the process of filter selection. That means the first filter in the list will be asked first and if not matched the next will be called etc. Here a value matches the 20 MB-sized filter min-value-size and will be stored in the path "data/20Mvalues", all other in "data/values".

<value-storages>
  <value-storage id="Storage #1" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage">
    <properties>
      <property name="path" value="data/20Mvalues"/>
    </properties>
    <filters>
      <filter property-type="Binary" min-value-size="20M"/>
    </filters>
  <value-storage>
  <value-storage id="Storage #2" class="org.exoplatform.services.jcr.impl.storage.value.fs.TreeFileValueStorage">
    <properties>
      <property name="path" value="data/values"/>
    </properties>
    <filters>
      <filter property-type="Binary" min-value-size="1M"/>
    </filters>
  <value-storage>
<value-storages>

eXo JCR supports Content-addressable storage feature for Values storing.

Content Addressable Value storage stores unique content once. Different properties (values) with same content will be stored as one data file shared between those values. We can tell the Value content will be shared across some Values in storage and will be stored on one physical file.

Storage size will be decreased for application which governs potentially same data in the content.

If property Value changes it is stored in an additional file. Alternatively the file is shared with other values, pointing to the same content.

The storage calculates Value content address each time the property was changed. CAS write operations are much more expensive compared to the non-CAS storages.

Content address calculation based on java.security.MessageDigest hash computation and tested with MD5 and SHA1 algorithms.

CAS support can be enabled for Tree and Simple File Value Storage types.

To enable CAS support just configure it in JCR Repositories configuration like we do for other Value Storages.

<workspaces>
        <workspace name="ws">
          <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
            <properties>
              <property name="source-name" value="jdbcjcr"/>
              <property name="dialect" value="oracle"/>
              <property name="multi-db" value="false"/>
              <property name="update-storage" value="false"/>
              <property name="max-buffer-size" value="200k"/>
              <property name="swap-directory" value="target/temp/swap/ws"/>
            </properties>
            <value-storages>
<!------------------- here ----------------------->
              <value-storage id="ws" class="org.exoplatform.services.jcr.impl.storage.value.fs.CASableTreeFileValueStorage">
                <properties>
                  <property name="path" value="target/temp/values/ws"/>
                  <property name="digest-algo" value="MD5"/>
                  <property name="vcas-type" value="org.exoplatform.services.jcr.impl.storage.value.cas.JDBCValueContentAddressStorageImpl"/>
                  <property name="jdbc-source-name" value="jdbcjcr"/>
                  <property name="jdbc-dialect" value="oracle"/>
                </properties>
                <filters>
                  <filter property-type="Binary"/>
                </filters>
              </value-storage>
            </value-storages>

Properties:

digest-algo - digest hash algorithm (MD5 and SHA1 were tested);
vcas-type - Value CAS internal data type, JDBC backed is currently implemented org.exoplatform.services.jcr.impl.storage.value.cas.JDBCValueContentAddressStorageImp;l
jdbc-source-name - JDBCValueContentAddressStorageImpl specific parameter, database will be used to save CAS metadata. It's simple to use same as in workspace container;
jdbc-dialect - JDBCValueContentAddressStorageImpl specific parameter, database dialect. It's simple to use same as in workspace container;

Table 6.1. 

ParameterDefaultDescriptionSince
index-dirnoneThe location of the index directory. This parameter is mandatory. Up to 1.9 this parameter called "indexDir"1.0
use-compoundfiletrueAdvises lucene to use compound files for the index files.1.9
min-merge-docs100Minimum number of nodes in an index until segments are merged.1.9
volatile-idle-time3Idle time in seconds until the volatile index part is moved to a persistent index even though minMergeDocs is not reached.1.9
max-merge-docsInteger.MAX_VALUEMaximum number of nodes in segments that will be merged. The default value changed in JCR 1.9 to Integer.MAX_VALUE.1.9
merge-factor10Determines how often segment indices are merged.1.9
max-field-length10000The number of words that are fulltext indexed at most per property.1.9
cache-size1000Size of the document number cache. This cache maps uuids to lucene document numbers1.9
force-consistencycheckfalseRuns a consistency check on every startup. If false, a consistency check is only performed when the search index detects a prior forced shutdown.1.9
auto-repairtrueErrors detected by a consistency check are automatically repaired. If false, errors are only written to the log.1.9
query-classQueryImplClass name that implements the javax.jcr.query.Query interface.This class must also extend from the class: org.exoplatform.services.jcr.impl.core.query.AbstractQueryImpl.1.9
document-ordertrueIf true and the query does not contain an 'order by' clause, result nodes will be in document order. For better performance when queries return a lot of nodes set to 'false'.1.9
result-fetch-sizeInteger.MAX_VALUEThe number of results when a query is executed. Default value: Integer.MAX_VALUE (-> all).1.9
excerptprovider-classDefaultXMLExcerptThe name of the class that implements org.exoplatform.services.jcr.impl.core.query.lucene.ExcerptProvider and should be used for the rep:excerpt() function in a query.1.9
support-highlightingfalseIf set to true additional information is stored in the index to support highlighting using the rep:excerpt() function.1.9
synonymprovider-classnoneThe name of a class that implements org.exoplatform.services.jcr.impl.core.query.lucene.SynonymProvider. The default value is null (-> not set).1.9
synonymprovider-config-pathnoneThe path to the synonym provider configuration file. This path interpreted relative to the path parameter. If there is a path element inside the SearchIndex element, then this path is interpreted relative to the root path of the path. Whether this parameter is mandatory depends on the synonym provider implementation. The default value is null (-> not set).1.9
indexing-configuration-pathnoneThe path to the indexing configuration file.1.9
indexing-configuration-classIndexingConfigurationImplThe name of the class that implements org.exoplatform.services.jcr.impl.core.query.lucene.IndexingConfiguration.1.9
force-consistencycheckfalseIf set to true a consistency check is performed depending on the parameter forceConsistencyCheck. If set to false no consistency check is performed on startup, even if a redo log had been applied.1.9
spellchecker-classnoneThe name of a class that implements org.exoplatform.services.jcr.impl.core.query.lucene.SpellChecker.1.9
errorlog-size50(Kb)The default size of error log file in Kb.1.9
upgrade-indexfalseAllows JCR to convert an existing index into the new format. Also it is possible to set this property via system property, for example: -Dupgrade-index=true Indexes before JCR 1.12 will not run with JCR 1.12. Hence you have to run an automatic migration: Start JCR with -Dupgrade-index=true. The old index format is then converted in the new index format. After the conversion the new format is used. On the next start you don't need this option anymore. The old index is replaced and a back conversion is not possible - therefore better take a backup of the index before. (Only for migrations from JCR 1.9 and later.)1.12
analyzerorg.apache.lucene.analysis.standard.StandardAnalyzerClass name of a lucene analyzer to use for fulltext indexing of text.1.12

By default Exo JCR uses the Lucene standard Analyzer to index contents. This analyzer uses some standard filters in the method that analyzes the content:

public TokenStream tokenStream(String fieldName, Reader reader) {
    StandardTokenizer tokenStream = new StandardTokenizer(reader, replaceInvalidAcronym);
    tokenStream.setMaxTokenLength(maxTokenLength);
    TokenStream result = new StandardFilter(tokenStream);
    result = new LowerCaseFilter(result);
    result = new StopFilter(result, stopSet);
    return result;
  }

For specific cases, you may wish to use additional filters like ISOLatin1AccentFilter, which replaces accented characters in the ISO Latin 1 character set (ISO-8859-1) by their unaccented equivalents.

In order to use a different filter, you have to create a new analyzer, and a new search index to use the analyzer. You put it in a jar, which is deployed with your application.

You may also add a condition to the index rule and have multiple rules with the same nodeType. The first index rule that matches will apply and all remaining ones are ignored:

<?xml version="1.0"?>
<!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd">
<configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
  <index-rule nodeType="nt:unstructured"
              boost="2.0"
              condition="@priority = 'high'">
    <property>Text</property>
  </index-rule>
  <index-rule nodeType="nt:unstructured">
    <property>Text</property>
  </index-rule>
</configuration>

In the above example the first rule only applies if the nt:unstructured node has a priority property with a value 'high'. The condition syntax supports only the equals operator and a string literal.

You may also reference properties in the condition that are not on the current node:

<?xml version="1.0"?>
<!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd">
<configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
  <index-rule nodeType="nt:unstructured"
              boost="2.0"
              condition="ancestor::*/@priority = 'high'">
    <property>Text</property>
  </index-rule>
  <index-rule nodeType="nt:unstructured"
              boost="0.5"
              condition="parent::foo/@priority = 'low'">
    <property>Text</property>
  </index-rule>
  <index-rule nodeType="nt:unstructured"
              boost="1.5"
              condition="bar/@priority = 'medium'">
    <property>Text</property>
  </index-rule>
  <index-rule nodeType="nt:unstructured">
    <property>Text</property>
  </index-rule>
</configuration>

The indexing configuration also allows you to specify the type of a node in the condition. Please note however that the type match must be exact. It does not consider sub types of the specified node type.

<?xml version="1.0"?>
<!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd">
<configuration xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
  <index-rule nodeType="nt:unstructured"
              boost="2.0"
              condition="element(*, nt:unstructured)/@priority = 'high'">
    <property>Text</property>
  </index-rule>
</configuration>

Sometimes it is useful to include the contents of descendant nodes into a single node to easier search on content that is scattered across multiple nodes.

JCR allows you to define index aggregates based on relative path patterns and primary node types.

The following example creates an index aggregate on nt:file that includes the content of the jcr:content node:

<?xml version="1.0"?>
<!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd">
<configuration xmlns:jcr="http://www.jcp.org/jcr/1.0"
               xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
  <aggregate primaryType="nt:file">
    <include>jcr:content</include>
  </aggregate>
</configuration>

You can also restrict the included nodes to a certain type:

<?xml version="1.0"?>
<!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd">
<configuration xmlns:jcr="http://www.jcp.org/jcr/1.0"
               xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
  <aggregate primaryType="nt:file">
    <include primaryType="nt:resource">jcr:content</include>
  </aggregate>
</configuration>

You may also use the * to match all child nodes:

<?xml version="1.0"?>
<!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd">
<configuration xmlns:jcr="http://www.jcp.org/jcr/1.0"
               xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
  <aggregate primaryType="nt:file">http://wiki.exoplatform.com/xwiki/bin/edit/JCR/Search+Configuration
    <include primaryType="nt:resource">*</include>
  </aggregate>
</configuration>

If you wish to include nodes up to a certain depth below the current node you can add multiple include elements. E.g. the nt:file node may contain a complete XML document under jcr:content:

<?xml version="1.0"?>
<!DOCTYPE configuration SYSTEM "http://www.exoplatform.org/dtd/indexing-configuration-1.0.dtd">
<configuration xmlns:jcr="http://www.jcp.org/jcr/1.0"
               xmlns:nt="http://www.jcp.org/jcr/nt/1.0">
  <aggregate primaryType="nt:file">
    <include>*</include>
    <include>*/*</include>
    <include>*/*/*</include>
  </aggregate>
</configuration>

When using analyzers, you may encounter an unexpected behavior when searching within a property compared to searching within a node scope. The reason is that the node scope always uses the global analyzer.

Let's suppose that the property "mytext" contains the text : "testing my analyzers" and that you haven't configured any analyzers for the property "mytext" (and not changed the default analyzer in SearchIndex).

If your query is for example:

xpath = "//*[jcr:contains(mytext,'analyzer')]"

This xpath does not return a hit in the node with the property above and default analyzers.

Also a search on the node scope

xpath = "//*[jcr:contains(.,'analyzer')]"

won't give a hit. Realize, that you can only set specific analyzers on a node property, and that the node scope indexing/analyzing is always done with the globally defined analyzer in the SearchIndex element.

Now, if you change the analyzer used to index the "mytext" property above to

<analyzer class="org.apache.lucene.analysis.Analyzer.GermanAnalyzer">
     <property>mytext</property>
</analyzer>

and you do the same search again, then for

xpath = "//*[jcr:contains(mytext,'analyzer')]"

you would get a hit because of the word stemming (analyzers - analyzer).

The other search,

xpath = "//*[jcr:contains(.,'analyzer')]"

still would not give a result, since the node scope is indexed with the global analyzer, which in this case does not take into account any word stemming.

In conclusion, be aware that when using analyzers for specific properties, you might find a hit in a property for some search text, and you do not find a hit with the same search text in the node scope of the property!

In order to run multilanguage JCR on an Oracle backend Unicode encoding for characters set should be applied to the database. Other Oracle globalization parameters don't make any impact. The only property to modify is NLS_CHARACTERSET.

We have tested NLS_CHARACTERSET = AL32UTF8 and it's works well for many European and Asian languages.

Example of database configuration (used for JCR testing):

NLS_LANGUAGE             AMERICAN
NLS_TERRITORY            AMERICA
NLS_CURRENCY             $
NLS_ISO_CURRENCY         AMERICA
NLS_NUMERIC_CHARACTERS   .,
NLS_CHARACTERSET         AL32UTF8
NLS_CALENDAR             GREGORIAN
NLS_DATE_FORMAT          DD-MON-RR
NLS_DATE_LANGUAGE        AMERICAN
NLS_SORT                 BINARY
NLS_TIME_FORMAT          HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT     DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT       HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT  DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY        $
NLS_COMP                 BINARY
NLS_LENGTH_SEMANTICS     BYTE
NLS_NCHAR_CONV_EXCP      FALSE
NLS_NCHAR_CHARACTERSET   AL16UTF16

Create database with Unicode encoding and use Oracle dialect for the Workspace Container:

<workspace name="collaboration">
          <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
            <properties>
              <property name="source-name" value="jdbcjcr" />
              <property name="dialect" value="oracle" />
              <property name="multi-db" value="false" />
              <property name="max-buffer-size" value="200k" />
              <property name="swap-directory" value="target/temp/swap/ws" />
            </properties>
          .....

DB2 Universal Database (DB2 UDB) supports UTF-8 and UTF-16/UCS-2. When a Unicode database is created, CHAR, VARCHAR, LONG VARCHAR data are stored in UTF-8 form. It's enough for JCR multi-lingual support.

Example of UTF-8 database creation:

DB2 CREATE DATABASE dbname USING CODESET UTF-8 TERRITORY US

Create database with UTF-8 encoding and use db2 dialect for Workspace Container on DB2 v.9 and higher:

<workspace name="collaboration">
          <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
            <properties>
              <property name="source-name" value="jdbcjcr" />
              <property name="dialect" value="db2" />
              <property name="multi-db" value="false" />
              <property name="max-buffer-size" value="200k" />
              <property name="swap-directory" value="target/temp/swap/ws" />
            </properties>
          .....

Note

For DB2 v.8.x support change the property "dialect" to db2v8.

JCR MySQL-backend requires special dialect MySQL-UTF8 to be used for internationalization support. But the database default charset should be latin1 to use limited index space effectively (1000 bytes for MyISAM engine, 767 for InnoDB). If database default charset is multibyte, a JCR database initialization error is thrown concerning index creation failure. In other words JCR can work on any singlebyte default charset of database, with UTF8 supported by MySQL server. But we have tested it only on latin1 database default charset.

Repository configuration, workspace container entry example:

<workspace name="collaboration">
          <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
            <properties>
              <property name="source-name" value="jdbcjcr" />
              <property name="dialect" value="mysql-utf8" />
              <property name="multi-db" value="false" />
              <property name="max-buffer-size" value="200k" />
              <property name="swap-directory" value="target/temp/swap/ws" />
            </properties>
          .....

On PostgreSQL-backend multilingual support can be enabled in different ways:

  • Using the locale features of the operating system to provide locale-specific collation order, number formatting, translated messages, and other aspects. UTF-8 is widely used on Linux distributions by default, so it can be useful in such case.

  • Providing a number of different character sets defined in the PostgreSQL server, including multiple-byte character sets, to support storing text any language, and providing character set translation between client and server. We recommend to use UTF-8 database charset, it will allow any-to-any conversations and make this issue transparent for the JCR.

Create database with UTF-8 encoding and use PgSQL dialect for Workspace Container:

<workspace name="collaboration">
          <container class="org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer">
            <properties>
              <property name="source-name" value="jdbcjcr" />
              <property name="dialect" value="pgsql" />
              <property name="multi-db" value="false" />
              <property name="max-buffer-size" value="200k" />
              <property name="swap-directory" value="target/temp/swap/ws" />
            </properties>
          .....

On startup RepositoryServiceConfiguration component checks if a configuration persister was configured. In that case it uses the provided ConfigurationPersister implementation class to instantiate the persister object.

Configuration with persister:

<component>
    <key>org.exoplatform.services.jcr.config.RepositoryServiceConfiguration</key>
    <type>org.exoplatform.services.jcr.impl.config.RepositoryServiceConfigurationImpl</type>
    <init-params>
      <value-param>
        <name>conf-path</name>
        <description>JCR configuration file</description>
        <value>/conf/standalone/exo-jcr-config.xml</value>
      </value-param>
      <properties-param>
        <name>working-conf</name>
        <description>working-conf</description>
        <property name="source-name" value="jdbcjcr" />
        <property name="dialect" value="mysql" />
        <property name="persister-class-name" value="org.exoplatform.services.jcr.impl.config.JDBCConfigurationPersister" />
      </properties-param>
    </init-params>
  </component>

Where:

ConfigurationPersister interface:

/**
   * Init persister.
   * Used by RepositoryServiceConfiguration on init. 
   * @return - config data stream
   */
  void init(PropertiesParam params) throws RepositoryConfigurationException;
  
  /**
   * Read config data.
   * @return - config data stream
   */
  InputStream read() throws RepositoryConfigurationException;
  
  /**
   * Create table, write data.
   * @param confData - config data stream
   */
  void write(InputStream confData) throws RepositoryConfigurationException;
  
  /**
   * Tell if the config exists.
   * @return - flag
   */
  boolean hasConfig() throws RepositoryConfigurationException;

JCR Core implementation contains a persister which stores the repository configuration in the relational database using JDBC calls - org.exoplatform.services.jcr.impl.config.JDBCConfigurationPersister.

The implementation will crate and use table JCR_CONFIG in the provided database.

But the developer can implement his own persister for his particular usecase.

To deploy eXo JCR to JBoss As follow next steps:

  1. Dowload the latest version of eXo JCR ear distribution.

  2. Copy <jcr.ear> into <%jboss_home%/server/default/deploy>

  3. Put exo-configuration.xml to the root <%jboss_home%/exo-configuration.xml>

  4. Configure JAAS by inserting XML fragment shown below into <%jboss_home%/server/default/conf/login-config.xml>

    <application-policy name="exo-domain">
       <authentication>
          <login-module code="org.exoplatform.services.security.j2ee.JbossLoginModule" flag="required"></login-module>
       </authentication>
    </application-policy>
  5. Ensure that you use JBossTS Transaction Service and JBossCache Transaction Manager. Your exo-configuration.xml must contain such parts:

    <component>
       <key>org.jboss.cache.transaction.TransactionManagerLookup</key>
       <type>org.jboss.cache.GenericTransactionManagerLookup</type>^
    </component>
    
    <component>
       <key>org.exoplatform.services.transaction.TransactionService</key>
       <type>org.exoplatform.services.transaction.jbosscache.JBossTransactionsService</type>
       <init-params>
          <value-param>
             <name>timeout</name>
             <value>300</value>
          </value-param>
       </init-params>
    </component>
  6. Start server:

    • bin/run.sh for Unix

    • bin/run.bat for Windows

  7. Try accessing http://localhost:8080/browser with root/exo as login/password if you have done everything right, you'll get access to repository browser.

  • To manually configure repository create a new configuration file (f.e. exo-jcr-configuration.xml). For details see JCR Configuration. Your configuration must look like:

    <repository-service default-repository="repository1">
       <repositories>
          <repository name="repository1" system-workspace="ws1" default-workspace="ws1">
             <security-domain>exo-domain</security-domain>
             <access-control>optional</access-control>
             <authentication-policy>org.exoplatform.services.jcr.impl.core.access.JAASAuthenticator</authentication-policy>
             <workspaces>
                <workspace name="ws1">
                   <container class="org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer">
                      <properties>
                         <property name="source-name" value="jdbcjcr" />
                         <property name="dialect" value="oracle" />
                         <property name="multi-db" value="false" />
                         <property name="update-storage" value="false" />
                         <property name="max-buffer-size" value="200k" />
                         <property name="swap-directory" value="../temp/swap/production" />
                      </properties>
                      <value-storages>
                         see "Value storage configuration" part.
                      </value-storages>
                   </container>
                   <initializer class="org.exoplatform.services.jcr.impl.core.ScratchWorkspaceInitializer">
                      <properties>
                         <property name="root-nodetype" value="nt:unstructured" />
                      </properties>
                   </initializer>
                   <cache enabled="true" class="org.exoplatform.services.jcr.impl.dataflow.persistent.jbosscache.JBossCacheWorkspaceStorageCache">
                         see  "Cache configuration" part.
                   </cache>
                   <query-handler class="org.exoplatform.services.jcr.impl.core.query.lucene.SearchIndex">
                      see  "Indexer configuration" part.
                   </query-handler>
                   <lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl">
                      see  "Lock Manager configuration" part.
                   </lock-manager>
                </workspace>
                <workspace name="ws2">
                            ...
                </workspace>
                <workspace name="wsN">
                            ...
                </workspace>
             </workspaces>
          </repository>
       </repositories>
    </repository-service> 
  • and update RepositoryServiceConfiguration configuration in exo-configuration.xml to use this file:

    <component>
       <key>org.exoplatform.services.jcr.config.RepositoryServiceConfiguration</key>
       <type>org.exoplatform.services.jcr.impl.config.RepositoryServiceConfigurationImpl</type>
       <init-params>
          <value-param>
             <name>conf-path</name>
             <description>JCR configuration file</description>
             <value>exo-jcr-configuration.xml</value>
          </value-param>
       </init-params>
    </component>

Configuration of every workspace in repository must contains of such parts:

Exo JCR implementation is shipped with ready-to-use JBoss Cache configuration templates for JCR's components. They are situated in application package in /conf/porta/ folder.

It's template name is "jbosscache-lock.xml"

<?xml version="1.0" encoding="UTF-8"?>
<jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1">

   <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false"
      lockAcquisitionTimeout="20000" />
   <clustering mode="replication" clusterName="${jbosscache-cluster-name}">
      <stateRetrieval timeout="20000" fetchInMemoryState="false" />
      <jgroupsConfig multiplexerStack="jcr.stack" />
      <sync />
   </clustering>
   <loaders passivation="false" shared="true">
      <preload>
         <node fqn="/" />
      </preload>
      <loader class="org.jboss.cache.loader.JDBCCacheLoader" async="false" fetchPersistentState="false"
         ignoreModifications="false" purgeOnStartup="false">
         <properties>
            cache.jdbc.table.name=${jbosscache-cl-cache.jdbc.table.name}
            cache.jdbc.table.create=${jbosscache-cl-cache.jdbc.table.create}
            cache.jdbc.table.drop=${jbosscache-cl-cache.jdbc.table.drop}
            cache.jdbc.table.primarykey=${jbosscache-cl-cache.jdbc.table.primarykey}
            cache.jdbc.fqn.column=${jbosscache-cl-cache.jdbc.fqn.column}
            cache.jdbc.fqn.type=${jbosscache-cl-cache.jdbc.fqn.type}
            cache.jdbc.node.column=${jbosscache-cl-cache.jdbc.node.column}
            cache.jdbc.node.type=${jbosscache-cl-cache.jdbc.node.type}
            cache.jdbc.parent.column=${jbosscache-cl-cache.jdbc.parent.column}
            cache.jdbc.datasource=${jbosscache-cl-cache.jdbc.datasource}
         </properties>
      </loader>
   </loaders>
</jbosscache>

CacheableLockManagerImpl stores Lock object in JBoss-cache, so Locks are replicable and affects on cluster, not only a single node. Also JBoss-cache has JDBCCacheLoader, so locks will be stored to database.

Both implementation supports Expired Locks removing. There is LockRemover - separate thread, that periodically ask LockManager for Locks that lives to much and must be removed. So, timeout for LockRemover may be set as follows, default value is 30m.

<properties>
   <property name="time-out" value="10m" />
   ...
</properties>

Replication requirements are same as for Cache

Full JCR configuration example you can see here.

Common tips:

  • clusterName ("jbosscache-cluster-name") must be unique;

  • cache.jdbc.table.name must be unique per datasource;

  • cache.jdbc.fqn.type must and cache.jdbc.node.type must be configured according to used database;

There is few ways how to configure CacheableLockManagerImpl, and all of them configures JBoss-cache and JDBCCacheLoader.

See http://community.jboss.org/wiki/JBossCacheJDBCCacheLoader

First one is - put JbossCache configuraion file path to CacheableLockManagerImpl

Config is:

<lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl">
   <properties>
     <property name="time-out" value="15m" />
     <property name="jbosscache-configuration" value="conf/standalone/cluster/test-jbosscache-lock-config.xml" />
   </properties>
</lock-manager>

test-jbosscache-lock-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.2">

 <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false" lockAcquisitionTimeout="20000" />

 <clustering mode="replication" clusterName="JBoss-Cache-Lock-Cluster_Name">
  <stateRetrieval timeout="20000" fetchInMemoryState="false" nonBlocking="true" />
  <jgroupsConfig>

   <TCP bind_addr="127.0.0.1" start_port="9800" loopback="true" recv_buf_size="20000000" send_buf_size="640000" discard_incompatible_packets="true"
    max_bundle_size="64000" max_bundle_timeout="30" use_incoming_packet_handler="true" enable_bundling="false" use_send_queues="false" sock_conn_timeout="300"
    skip_suspected_members="true" use_concurrent_stack="true" thread_pool.enabled="true" thread_pool.min_threads="1" thread_pool.max_threads="25"
    thread_pool.keep_alive_time="5000" thread_pool.queue_enabled="false" thread_pool.queue_max_size="100" thread_pool.rejection_policy="run"
    oob_thread_pool.enabled="true" oob_thread_pool.min_threads="1" oob_thread_pool.max_threads="8" oob_thread_pool.keep_alive_time="5000"
    oob_thread_pool.queue_enabled="false" oob_thread_pool.queue_max_size="100" oob_thread_pool.rejection_policy="run" />
   <MPING timeout="2000" num_initial_members="2" mcast_port="34540" bind_addr="127.0.0.1" mcast_addr="224.0.0.1" />


   <MERGE2 max_interval="30000" min_interval="10000" />
   <FD_SOCK />
   <FD max_tries="5" shun="true" timeout="10000" />
   <VERIFY_SUSPECT timeout="1500" />
   <pbcast.NAKACK discard_delivered_msgs="true" gc_lag="0" retransmit_timeout="300,600,1200,2400,4800" use_mcast_xmit="false" />
   <UNICAST timeout="300,600,1200,2400,3600" />
   <pbcast.STABLE desired_avg_gossip="50000" max_bytes="400000" stability_delay="1000" />
   <pbcast.GMS join_timeout="5000" print_local_addr="true" shun="false" view_ack_collection_timeout="5000" view_bundling="true" />
   <FRAG2 frag_size="60000" />
   <pbcast.STREAMING_STATE_TRANSFER />
  <pbcast.FLUSH timeout="0" />

  </jgroupsConfig

  <sync />
 </clustering>

 <loaders passivation="false" shared="true">
  <preload>
   <node fqn="/" />
  </preload>
  <loader class="org.jboss.cache.loader.JDBCCacheLoader" async="false" fetchPersistentState="false" ignoreModifications="false" purgeOnStartup="false">
   <properties>
    cache.jdbc.table.name=jcrlocks_ws
    cache.jdbc.table.create=true
    cache.jdbc.table.drop=false
    cache.jdbc.table.primarykey=jcrlocks_ws_pk
    cache.jdbc.fqn.column=fqn
    cache.jdbc.fqn.type=VARCHAR(512)
    cache.jdbc.node.column=node
    cache.jdbc.node.type=<BLOB>  
    cache.jdbc.parent.column=parent
    cache.jdbc.datasource=jdbcjcr
   </properties>
  </loader>

 </loaders>

</jbosscache>

Configuration requirements:

Second one is - use template JBoss-cache configuration for all LockManagers

Lock template configuration

test-jbosscache-lock.xml

<?xml version="1.0" encoding="UTF-8"?>
<jbosscache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:jboss:jbosscache-core:config:3.1">

   <locking useLockStriping="false" concurrencyLevel="50000" lockParentForChildInsertRemove="false"
      lockAcquisitionTimeout="20000" />

   <clustering mode="replication" clusterName="${jbosscache-cluster-name}">
      <stateRetrieval timeout="20000" fetchInMemoryState="false" />
      <jgroupsConfig multiplexerStack="jcr.stack" />
      <sync />
   </clustering>

   <loaders passivation="false" shared="true">
      <!-- All the data of the JCR locks needs to be loaded at startup -->
      <preload>
         <node fqn="/" />
      </preload>  
      <!--
      For another cache-loader class you should use another template with
      cache-loader specific parameters
      ->
      <loader class="org.jboss.cache.loader.JDBCCacheLoader" async=q"false" fetchPersistentState="false"
         ignoreModifications="false" purgeOnStartup="false">
         <properties>
            cache.jdbc.table.name=${jbosscache-cl-cache.jdbc.table.name}
            cache.jdbc.table.create=${jbosscache-cl-cache.jdbc.table.create}
            cache.jdbc.table.drop=${jbosscache-cl-cache.jdbc.table.drop}
            cache.jdbc.table.primarykey=${jbosscache-cl-cache.jdbc.table.primarykey}
            cache.jdbc.fqn.column=${jbosscache-cl-cache.jdbc.fqn.column}
            cache.jdbc.fqn.type=${jbosscache-cl-cache.jdbc.fqn.type}
            cache.jdbc.node.column=${jbosscache-cl-cache.jdbc.node.column}
            cache.jdbc.node.type=${jbosscache-cl-cache.jdbc.node.type}
            cache.jdbc.parent.column=${jbosscache-cl-cache.jdbc.parent.column}
            cache.jdbc.datasource=${jbosscache-cl-cache.jdbc.datasource}
         </properties>
      </loader>
   </loaders>
</jbosscache>

As you see, all configurable paramaters filled by templates and will be replaced by LockManagers conf parameters:

<lock-manager class="org.exoplatform.services.jcr.impl.core.lock.jbosscache.CacheableLockManagerImpl">
   <properties>
      <property name="time-out" value="15m" />
      <property name="jbosscache-configuration" value="test-jbosscache-lock.xml" />
      <property name="jgroups-configuration" value="udp-mux.xml" />
      <property name="jgroups-multiplexer-stack" value="true" />
      <property name="jbosscache-cluster-name" value="JCR-cluster-locks-ws" />
      <property name="jbosscache-cl-cache.jdbc.table.name" value="jcrlocks_ws" />
      <property name="jbosscache-cl-cache.jdbc.table.create" value="true" />
      <property name="jbosscache-cl-cache.jdbc.table.drop" value="false" />
      <property name="jbosscache-cl-cache.jdbc.table.primarykey" value="jcrlocks_ws_pk" />
      <property name="jbosscache-cl-cache.jdbc.fqn.column" value="fqn" />
      <property name="jbosscache-cl-cache.jdbc.fqn.type" value="AUTO"/>
      <property name="jbosscache-cl-cache.jdbc.node.column" value="node" />
      <property name="jbosscache-cl-cache.jdbc.node.type" value="AUTO"/>
      <property name="jbosscache-cl-cache.jdbc.parent.column" value="parent" />
      <property name="jbosscache-cl-cache.jdbc.datasource" value="jdbcjcr" />
   </properties>
</lock-manager>

Configuration requirements:

our-udp-mux.xml

<protocol_stacks>
   <stack name="jcr.stack">
      <config>
         <UDP mcast_addr="228.10.10.10" mcast_port="45588" tos="8" ucast_recv_buf_size="20000000"
            ucast_send_buf_size="640000" mcast_recv_buf_size="25000000" mcast_send_buf_size="640000" loopback="false"
            discard_incompatible_packets="true" max_bundle_size="64000" max_bundle_timeout="30"
            use_incoming_packet_handler="true" ip_ttl="2" enable_bundling="true" enable_diagnostics="true"
            thread_naming_pattern="cl" use_concurrent_stack="true" thread_pool.enabled="true" thread_pool.min_threads="2"
            thread_pool.max_threads="8" thread_pool.keep_alive_time="5000" thread_pool.queue_enabled="true"
            thread_pool.queue_max_size="1000" thread_pool.rejection_policy="discard" oob_thread_pool.enabled="true"
            oob_thread_pool.min_threads="1" oob_thread_pool.max_threads="8" oob_thread_pool.keep_alive_time="5000"
            oob_thread_pool.queue_enabled="false" oob_thread_pool.queue_max_size="100" oob_thread_pool.rejection_policy="Run" />

         <PING timeout="2000" num_initial_members="3" />
         <MERGE2 max_interval="30000" min_interval="10000" />
         <FD_SOCK />
         <FD timeout="10000" max_tries="5" shun="true" />
         <VERIFY_SUSPECT timeout="1500" />
         <BARRIER />
         <pbcast.NAKACK use_stats_for_retransmission="false" exponential_backoff="150" use_mcast_xmit="true"
            gc_lag="0" retransmit_timeout="50,300,600,1200" discard_delivered_msgs="true" />
         <UNICAST timeout="300,600,1200" />
         <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000" max_bytes="1000000" />
         <VIEW_SYNC avg_send_interval="60000" />
         <pbcast.GMS print_local_addr="true" join_timeout="3000" shun="false" view_bundling="true" />
         <FC max_credits="500000" min_threshold="0.20" />
         <FRAG2 frag_size="60000" />
         <!--pbcast.STREAMING_STATE_TRANSFER /-->
         <pbcast.STATE_TRANSFER />
         <!-- pbcast.FLUSH  /-->
      </config>
   </stack>
</protocol_stacks> 

Lets talk about indexing content in cluster.

For couple of reasons, we can't replicate index. That's means, some data added and indexed on one cluster node, will be replicated to another cluster node, but will not be indexed on that node.

So, how do the indexing works in cluster environment?

As, we can not index same data on all nodes of cluster, we must index it on one node. Node, that can index data and do changes on lucene index, is called "coordinator". Coordinator-node is choosen automaticaly, so we do not need special configuration for coordinator.

But, how can another nodes save their changes to lucene index?

First of all, data is already saved and replicated to another cluster-nodes, so we need only deliver message like "we need to index this data" to coordinator. Thats why Jboss-cache is used.

All nodes of cluster writes messages into JBoss-cache but only coordinator takes those messages and makes changes Lucene index.

How do the search works in cluster environment?

Search engine do not works with indexer, coordinator, etc. Search needs only lucene index. But only one cluster node can change lucene index - asking you. Yes - lucene index is shared. So, all cluster nodes must be configured to use lucene index from shared directory.

A little bit about indexing process (no matter, cluster or not) Indexer do not writes changes to FS lucene index immediately. At first, Indexer writes changes to Volatile index. If Volatile index size become 1Mb or more it is flushed to FS. Also there is timer, that flushes volatile index by timeout. Volatile index timeout configured by "max-volatile-time" paremeter.

See more about Search Configuration.

Common scheme of Shared Index

In order to have a better idea of the time spent into the database access layer, it cans be interesting to get some statistics on that part of the code, knowing that most of the time spent into eXo JCR is mainly the database access. This statistics will then allow you to identify without using any profiler what is anormally slow in this layer, which could help to fix the problem quickly.

In case you use org.exoplatform.services.jcr.impl.storage.jdbc.optimisation.CQJDBCWorkspaceDataContainer or org.exoplatform.services.jcr.impl.storage.jdbc.JDBCWorkspaceDataContainer as WorkspaceDataContainer, you can get statistics on the time spent into the database access layer. The database access layer (in eXo JCR) is represented by the methods of the interface org.exoplatform.services.jcr.storage.WorkspaceStorageConnection, so for all the methods defined in this interface, we can have the following figures:

Those figures are also available globaly for all the methods which gives us the global behavior of this layer.

If you want to enable the statistics, you just need to set the JVM parameter called JDBCWorkspaceDataContainer.statistics.enabled to true. The corresponding CSV file is StatisticsJDBCStorageConnection-${creation-timestamp}.csv for more details about how the csv files are managed please refer to the section dedicated to the statistics manager.

The format of each column header is ${method-alias}-${metric-alias}. The metric alias are described in the statistics manager section.


In order to know exactly how your application uses eXo JCR, it cans be interesting to register all the JCR API accesses in order to easily create real life test scenario based on pure JCR calls and also to tune your eXo JCR to better fit your requirements.

In order to allow you to specify into the configuration which part of eXo JCR needs to be monitored whitout applying any changes in your code and/or building anything, we choosed to rely on the Load-time Weaving proposed by AspectJ.

To enable this feature, you will have to add in your classpath the following jar files:

You will also need to get aspectjweaver-1.6.8.jar from the main maven repository http://repo2.maven.org/maven2/org/aspectj/aspectjweaver. At this stage, to enable the statistics on the JCR API accesses, you will need to add the JVM parameter -javaagent:${pathto}/aspectjweaver-1.6.8.jar to your command line, for more details please refer to http://www.eclipse.org/aspectj/doc/released/devguide/ltw-configuration.html.

By default, the configuration will collect statistcs on all the methods of the internal interfaces org.exoplatform.services.jcr.core.ExtendedSession and org.exoplatform.services.jcr.core.ExtendedNode, and the JCR API interface javax.jcr.Property. To add and/or remove some interfaces to monitor, you have two configuration files to change that are bundled into the jar exo.jcr.component.statistics-X.Y.Z.jar, which are conf/configuration.xml and META-INF/aop.xml.

The file content below is the content of conf/configuration.xml that you will need to modify to add and/or remove the full qualified name of the interfaces to monitor, into the list of parameter values of the init param called targetInterfaces.

<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd http://www.exoplaform.org/xml/ns/kernel_1_0.xsd"
 xmlns="http://www.exoplaform.org/xml/ns/kernel_1_0.xsd">

 <component>
   <type>org.exoplatform.services.jcr.statistics.JCRAPIAspectConfig</type>
   <init-params>
     <values-param>
       <name>targetInterfaces</name>
       <value>org.exoplatform.services.jcr.core.ExtendedSession</value>
       <value>org.exoplatform.services.jcr.core.ExtendedNode</value>
       <value>javax.jcr.Property</value>
     </values-param>
   </init-params>
  </component>
</configuration>

The file content below is the content of META-INF/aop.xml that you will to need to modify to add and/or remove the full qualified name of the interfaces to monitor, into the expression filter of the pointcut called JCRAPIPointcut. As you can see below, by default only JCR API calls from the exoplatform packages are took into account, don't hesistate to modify also this filter to add your own package names.

<aspectj>
  <aspects>
    <concrete-aspect name="org.exoplatform.services.jcr.statistics.JCRAPIAspectImpl" extends="org.exoplatform.services.jcr.statistics.JCRAPIAspect">
      <pointcut name="JCRAPIPointcut"
        expression="(target(org.exoplatform.services.jcr.core.ExtendedSession) || target(org.exoplatform.services.jcr.core.ExtendedNode) || target(javax.jcr.Property)) &amp;&amp; call(public * *(..))" />
    </concrete-aspect>
  </aspects>
  <weaver options="-XnoInline">
    <include within="org.exoplatform..*" />
  </weaver>
</aspectj> 

The corresponding CSV files are of type Statistics${interface-name}-${creation-timestamp}.csv for more details about how the csv files are managed please refer to the section dedicated to the statistics manager.

The format of each column header is ${method-alias}-${metric-alias}. The method alias will be of type ${method-name}(list of parameter types separeted by ; to be compatible with the CSV format).

The metric alias are described in the statistics manager section.

Please note that this feature will affect the performances of eXo JCR so it must be used with caution.

The statistics manager manages all the statistics provided by eXo JCR, it is responsible of printing the data into the CSV files but also to expose the statistics through JMX and/or Rest.

The statistics manager will create all the CSV files for each category of statistics that it manages, the format of those files is Statistics${category-name}-${creation-timestamp}.csv. Those files will be created into the user directory if it is possible otherwise it will create them into the temporary directory. The format of those files is CSV (i.e. Comma-Seperated Values), one new line will be added regularily (every 5 seconds by default) and one last line will be added at JVM exit. Each line, will be composed of the 5 figures described below for each method and globaly for all the methods.


You can disable the persistence of the statistics by setting the JVM parameter called JCRStatisticsManager.persistence.enabled to false, by default it is set to true. You can aslo define the period of time between each record (i.e. line of data into the file) by setting the JVM parameter called JCRStatisticsManager.persistence.timeout to your expected value expressed in milliseconds, by default it is set to 5000.

You can also access to the statistics thanks to JMX, the available methods are the following:

Table 15.3. JMX Methods

getMinGives the minimum time spent into the method corresponding to the given category name and statistics name. The expected arguments are the name of the category of the statistics (e.g. JDBCStorageConnection) and the name of the expected method or global for the global value.
getMaxGives the maximum time spent into the method corresponding to the given category name and statistics name. The expected arguments are the name of the category of the statistics (e.g. JDBCStorageConnection) and the name of the expected method or global for the global value.
getTotalGives the total amount of time spent into the method corresponding to the given category name and statistics name. The expected arguments are the name of the category of the statistics (e.g. JDBCStorageConnection) and the name of the expected method or global for the global value.
getAvgGives the average time spent into the method corresponding to the given category name and statistics name. The expected arguments are the name of the category of the statistics (e.g. JDBCStorageConnection) and the name of the expected method or global for the global value.
getTimesGives the total amount of times the method has been called corresponding to the given category name and statistics name. The expected arguments are the name of the category of the statistics (e.g. JDBCStorageConnection) and the name of the expected method or global for the global value.
resetReset the statistics for the given category name and statistics name. The expected arguments are the name of the category of the statistics (e.g. JDBCStorageConnection) and the name of the expected method or global for the global value.
resetAllReset all the statistics for the given category name. The expected argument is the name of the category of the statistics (e.g. JDBCStorageConnection).


The full name of the related MBean is exo:service=statistic, view=jcr.

To be effective the namespace URI http://www.exoplaform.org/xml/ns/kernel_1_1.xsd must be target namespace of the XML configuration file.

<xsd:schema
     targetNamespace="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd"
     xmlns="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     elementFormDefault="qualified"
     attributeFormDefault="unqualified"
     version="1.0">

   ...
</xsd:schema>

eXo Portal uses PicoContainer, which implements the Inversion of Control (IoC) design pattern. All eXo containers inherit from a PicoContainer. There are mainly two eXo containers used, each of them can provide one or several services. Each container service is delivered in a JAR file. This JAR file may contain a default configuration. The use of default configurations is recommended and most services provide it.

When a Pico Container searches for services and its configurations, each configurable service may be reconfigured to override default values or set additional parameters. If the service is configured in two or more places the configuration override mechanism will be used.

The container performs the following steps making eXo Container configuration retrieval depending on the container type.

After the processing of all configurations available in system the container will initialize it and start each service in order of the dependency injection (DI).

The user/developer should be careful when configuring the same service in different configuration files. It's recommended to configure a service in its own JAR only. Or, in case of a portal configuration, strictly reconfigure the services in portal WAR files or in an external configuration.

There are services that can be (or should be) configured more than one time. This depends on 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 (shared with other services too). In the first case it's critical who will be the last, i.e. whose configuration will be used. In the second case it's no matter who is the first and who is the last (if the parameter objects are independent).

Since eXo JCR 1.12, we added a set of new features that have been designed to extend portal applications such as GateIn.

Now we can define precisely a portal container and its dependencies and settings thanks to the PortalContainerDefinition that currently contains the name of the portal container, the name of the rest context, the name of the realm he web application dependencies ordered by loading priority (i.e. the first dependency must be loaded at first and so on..) and the settings.

To be able to define a PortalContainerDefinition, we need to ensure first of all that a PortalContainerConfig has been defined at the RootContainer level, see below an example:

  <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>
      <!-- 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>

A new PortalContainerDefinition can be defined at the RootContainer level thanks to an external plugin, see below an example:

  <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>

Table 17.2. Descriptions of the fields of PortalContainerDefinition when it is used to define a new portal container

nameThe name of the portal container. This field is mandatory .
restContextNameThe name of the context name of the rest web application. This field is optional. The default value will the value define at the PortalContainerConfig level.
realmNameThe name of the realm. This field is optional. The default value will the value define at the PortalContainerConfig level.
dependenciesAll the dependencies of the portal container ordered by loading priority. This field is optional. The default value will the value define 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. This field is optional. The dependency order is really crucial since it will be interpreted the same way by several components of the platform. All those components, will consider the 1st element in the list less important than the second element and so on. It is currently used to:
  • Know the loading order of all the dependencies.

  • If we have several PortalContainerConfigOwner

    • The ServletContext of all the PortalContainerConfigOwner will be unified, if we use the unified ServletContext (PortalContainer.getPortalContext()) to get a resource, it will try to get the resource in the ServletContext of the most important PortalContainerConfigOwner (i.e. last in the dependency list) and if it cans find it, it will try with the second most important PortalContainerConfigOwner and so on.

    • The ClassLoader of all the PortalContainerConfigOwner will be unified, if we use the unified ClassLoader (PortalContainer.getPortalClassLoader()) to get a resource, it will try to get the resource in the ClassLoader of the most important PortalContainerConfigOwner (i.e. last in the dependency list) and if it cans find it, it will try with the second most important PortalContainerConfigOwner and so on.

settingsA java.util.Map of internal parameters that we would like to tie the portal container. Those parameters could have any type of value. This field is optional. If some internal settings are defined at the PortalContainerConfig level, the two maps of settings will be merged. If a setting with the same name is defined in both maps, it will keep the value defined at the PortalContainerDefinition level.
externalSettingsPathThe 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 maps of settings will be 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. The path doesn't contain any prefix of type "classpath:", "jar:" or "file:", we assume that the file could be externalized so we apply the following rules:

    1. A file exists at ${exo-conf-dir}/portal/${portalContainerName}/${externalSettingsPath}, we will load this file.

    2. No file exists at the previous path, we then assume that the path cans be interpreted by the ConfigurationManager.

  2. The path contains a prefix, we then assume that the path cans be interpreted by the ConfigurationManager.


Table 17.3. Descriptions of the fields of PortalContainerDefinition when it is used to define the default portal container

nameThe name of the portal container. This field is optional. The default portal name will be:
  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.portal.container is not empty, then 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 will be "portal".

restContextNameThe name of the context name of the rest web application. This field is optional. The default value wil be:
  1. If this field is not empty, then the default value will be the value of this field.

  2. f 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. f this field and the parameter default.rest.context are both empty, the default value will be "rest".

realmNameThe name of the realm. This field is optional. The default value wil be:
  1. If this field is not empty, then the default value will be the value of this field.

  2. f this field is empty and the value of the parameter default.realm.name is not empty, then the default value will be the value of the parameter.

  3. f this field and the parameter default.realm.name are both empty, the default value will be "exo-domain".

dependenciesAll the dependencies of the portal container ordered by loading priority. This field is optional. If this field has a non empty value, it will be the default list of dependencies.
settingsA java.util.Map of internal parameters that we would like to tie the default portal container. Those parameters could have any type of value. This field is optional.
externalSettingsPathThe 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 will be interpreted as follows:
  1. The path doesn't contain any prefix of type "classpath:", "jar:" or "file:", we assume that the file could be externalized so we apply the following rules:

    1. A file exists at ${exo-conf-dir}/portal/${externalSettingsPath}, we will load this file.

    2. No file exists at the previous path, we then assume that the path cans be interpreted by the ConfigurationManager.

  2. The path contains a prefix, we then assume that the path cans be interpreted by the ConfigurationManager.


Internal and external settings are both optional, but if we give a non empty value for both the application will merge the settings. If the same setting name exists in both settings, we apply the following rules:

  1. The value of the external setting is null, we ignore the value.

  2. The value of the external setting is not null and the value of the internal setting is null, the final value will be the external setting value that is of type String.

  3. Both values are not null, we will have to convert the external setting value into the target type which is the type of the internal setting value, thanks to the static method valueOf(String), the following sub-rules are then applied:

    1. The method cannot be found, the final value will be the external setting value that is of type String.

    2. The method can be found and the external setting value is an empty String, we ignore the external setting value.

    3. The method can be found and the external setting value is not an empty String but the method call fails, we ignore the external setting value.

    4. The method can be found and the external setting value is not an empty String and the method call succeeds, the final value will be the external setting value that is of type of the internal setting value.

We can inject the value of the portal container settings into the portal container configuration files thanks to the variables which name start with "portal.container.", so to get the value of a setting called "foo" just use the following syntax ${portal.container.foo}. You can also use internal variables, such as:


You can find below an example of how to use the variables:

<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_1.xsd http://www.exoplaform.org/xml/ns/kernel_1_1.xsd"
  xmlns="http://www.exoplaform.org/xml/ns/kernel_1_1.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>

In the properties file corresponding to the external settings, you can reuse variables previously defined (in the external settings or in the internal settings) 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}

In the external and internal settings, you can also use create variables based on value of System paramaters. The System parameters can either be defined at launch time or thanks to the PropertyConfigurator (see next section for more details). See an example below:

temp-dir=${java.io.tmpdir}${file.separator}my-temp

However, for the internal settings you can use System parameters only to define settings of type java.lang.String.

It cans be also very usefull to define a generic variable in the settings of the default portal container, the value of this variable will change according to the current portal container. See below an example:

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 "foo" will be value of the portal container "foo".

A new property configurator service has been developed for taking care of configuring system properties from the inline kernel configuration or from specified property files.

The services is scoped at the root container level because it is used by all the services in the different portal containers in the application runtime.

The kernel configuration is able to handle configuration profiles at runtime (as opposed to packaging time).

Profiles are configured in the configuration files of the eXo kernel.

A configuration element is profiles capable when it carries a profiles element.

All applications on the top of eXo JCR that need a cache, can rely on an org.exoplatform.services.cache.ExoCache instance that is managed by the org.exoplatform.services.cache.CacheService. The main implementation of this service is org.exoplatform.services.cache.impl.CacheServiceImpl which depends on the org.exoplatform.services.cache.ExoCacheConfig in order to create new ExoCache instances. See below an example of org.exoplatform.services.cache.CacheService definition:

  <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>600</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>

See below an example of how to define a new ExoCacheConfig thanks to a external-component-plugin:

  <external-component-plugins>
    <target-component>org.exoplatform.services.cache.CacheService</target-component>
    <component-plugin>
      <name>addExoCacheConfig</name>
      <set-method>addExoCacheConfig</set-method>
      <type>org.exoplatform.services.cache.ExoCacheConfigPlugin</type>
      <description>Configures the cache for query service</description>
      <init-params>
        <object-param>
          <name>cache.config.wcm.composer</name>
          <description>The default cache configuration</description>
          <object type="org.exoplatform.services.cache.ExoCacheConfig">
            <field name="name"><string>wcm.composer</string></field>
            <field name="maxSize"><int>300</int></field>
            <field name="liveTime"><long>600</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-plugin>
  </external-component-plugins>

The factory for jboss cache, delegates the cache creation to ExoCacheCreator that is defines as below:

package org.exoplatform.services.cache.impl.jboss;
...
public interface ExoCacheCreator {

  /**
   * Creates an eXo cache according to the given configuration {@link org.exoplatform.services.cache.ExoCacheConfig}
   * @param config the configuration of the cache to apply
   * @param cache the cache to initialize
   * @exception ExoCacheInitException if an exception happens while initializing the cache
   */
  public ExoCache create(ExoCacheConfig config, Cache<Serializable, Object> cache) throws ExoCacheInitException;
  
  /**
   * Returns the type of {@link org.exoplatform.services.cache.ExoCacheConfig} expected by the creator  
   * @return the expected type
   */
  public Class<? extends ExoCacheConfig> getExpectedConfigType();
  
  /**
   * Returns the name of the implementation expected by the creator. This is mainly used to be backward compatible
   * @return the expected by the creator
   */
  public String getExpectedImplementation();
}

The ExoCacheCreator allows you to define any kind of jboss cache instance that you would like to have. It has been designed to give you the ability to have your own type of configuration and to always be backward compatible.

In an ExoCacheCreator, you need to implement 3 methods which are:

By default, no cache creator are defined, so you need to define them yourself by adding them in your configuration files.

You have 2 ways to define a cache which are:

Make sure you understand the Java Naming and Directory InterfaceTM (JNDI) concepts before using this service.

The InitialContextInitializer configuration example:

  <component>
    <type>org.exoplatform.services.naming.InitialContextInitializer</type>
    <init-params>
      <properties-param>
        <name>default-properties</name>
        <description>Default initial context properties</description>
        <property name="java.naming.factory.initial" value="org.exoplatform.services.naming.SimpleContextFactory"/>
      </properties-param>
      <properties-param>
        <name>mandatory-properties</name>
        <description>Mandatory initial context properties</description>
        <property name="java.naming.provider.url" value="rmi://localhost:9999"/>
      </properties-param>
    </init-params>
  </component>

The BindReferencePlugin component plugin configuration example (for JDBC datasource):

  <component-plugins> 
    <component-plugin> 
      <name>bind.datasource</name>
      <set-method>addPlugin</set-method>
      <type>org.exoplatform.services.naming.BindReferencePlugin</type>
      <init-params>
        <value-param>
          <name>bind-name</name>
          <value>jdbcjcr</value>
        </value-param>
        <value-param>
          <name>class-name</name>
          <value>javax.sql.DataSource</value>
        </value-param>  
        <value-param>
          <name>factory</name>
          <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
        </value-param>
        <properties-param>
          <name>ref-addresses</name>
          <description>ref-addresses</description>
          <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
          <property name="url" value="jdbc:hsqldb:file:target/temp/data/portal"/>
          <property name="username" value="sa"/>
          <property name="password" value=""/>
        </properties-param>     
      </init-params>    
  </component-plugin>

InitialContextInitalizer also provides feature of references binding in runtime. References have bind in runtime will be persisted and automatically rebinded on a next system start. Java temp directory is used to persist references in bind-references.xml file.

Service provide methods for binding reference.

     public void bind(String bindName, 
                      String className, 
                      String factory, 
                      String factoryLocation, 
                      Map<String, String> refAddr) 
                 throws NamingException, FileNotFoundException, XMLStreamException;

Example of usage:

      // obtain InitialContextInitializer instance from ExoContainer (e.g. PortalContainer)
      InitialContextInitializer initContext = (InitialContextInitializer)container.getComponentInstanceOfType(InitialContextInitializer.class);
  
      Map<String, String> refAddr = new HashMap<String, String>();
      refAddr.put("driverClassName", "oracle.jdbc.OracleDriver");
      refAddr.put("url", "jdbc:oracle:thin:@oraclehost:1521:orcl");
      refAddr.put("username", "exouser");
      refAddr.put("password", "exopassword");

      initContext.bind("jdbcexco", "javax.sql.DataSource", "org.apache.commons.dbcp.BasicDataSourceFactory", null, refAddr);

      // try to get just bound DataSource
      DataSource ds = (DataSource)new InitialContext().lookup("jdbcexo");

Log4J is a very popular and flexible logging system. It is a good option for JBoss.

  <component>
    <type>org.exoplatform.services.log.LogConfigurationInitializer</type>
    <init-params>
      <value-param>
        <name>logger</name>
        <value>org.exoplatform.services.log.impl.BufferedLog4JLogger</value>
      </value-param>
      <value-param>
        <name>configurator</name>
        <value>org.exoplatform.services.log.impl.Log4JConfigurator</value>
      </value-param>
      <properties-param>
        <name>properties</name>
        <description>Log4J properties</description>
        <property name="log4j.rootLogger" value="DEBUG, stdout, file"/>
        <property name="log4j.appender.stdout" value="org.apache.log4j.ConsoleAppender"/>
        <property name="log4j.appender.stdout.layout" value="org.apache.log4j.PatternLayout"/>
        <property name="log4j.appender.stdout.layout.ConversionPattern" value="%d {dd.MM.yyyy HH:mm:ss} %c {1}: %m (%F, line %L) %n"/>
        <property name="log4j.appender.file" value="org.apache.log4j.FileAppender"/>
        <property name="log4j.appender.file.File" value="jcr.log"/>
        <property name="log4j.appender.file.layout" value="org.apache.log4j.PatternLayout"/>
        <property name="log4j.appender.file.layout.ConversionPattern" value="%d{dd.MM.yyyy HH:mm:ss} %m (%F, line %L) %n"/>
      </properties-param >
    </init-params>
  </component>

Service's configuration.

   <component>
      <key>org.exoplatform.services.database.creator.DBCreator</key>
      <type>org.exoplatform.services.database.creator.DBCreator</type>
      <init-params>
      <properties-param>
            <name>db-connection</name>
            <description>database connection properties</description>
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://localhost/" />
            <property name="username" value="root" />
            <property name="password" value="admin" />
         </properties-param>
         <properties-param>
            <name>db-creation</name>.
            <description>database creation properties</description>.
            <property name="scriptPath" value="script.sql" />
            <property name="username" value="testuser" />
            <property name="password" value="testpwd" />
         </properties-param>
      </init-params>
   </component>

db-connection properties section contains parameters needed for connection to database server

db-creation properties section contains paramaters for database creation using DDL script:

Specific db-connection properties section for different databases.

MySQL:

<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/" />
<property name="username" value="root" />
<property name="password" value="admin" />

PostgreSQL:

<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://localhost/" />
<property name="username" value="root" />
<property name="password" value="admin" />

MSSQL:

<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://localhost:1433;"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>

Sybase:

<property name="driverClassName" value="com.sybase.jdbc3.jdbc.SybDriver" />
<property name="url" value="jdbc:sybase:Tds:localhost:5000/"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>

Oracle:

<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@db2.exoua-int:1521:orclvm" />
<property name="username" value="root" />
<property name="password" value="admin" />