You are looking at documentation for an older release. Not what you want? See the current release documentation.
The container package is responsible of building a hierarchy of containers. Each service will then be registered in one container or the other according to the XML configuration file it is defined in. It is important to understand that there can be several PortalContainer instances that all are children of the RootContainer.
The behavior of the hierarchy is similar to a class loader one. Hence, when you look up a service that depends on another one, the container will look for it in the current container. If it cannot be found, it will look in the parent container. In that way, you can load all the reusable business logic components in the same container (here the RootContainer) and differentiate the service implementation from one portal instance to the other by just loading different service implementations in two sibling PortalContainers.
Therefore, if you look at the Portal Container as a service repository for all the business logics in a portal instance, then you understand why several PortalContainers allow you to manage several portals (each one deployed as a single war) in the same server by just changing XML configuration files.
The default configuration XML files are packaged in the service jar.
There are three configuration.xml
files, one for each container type. In
that XML file, we define the list of services and their init parameters
that will be loaded in the corresponding container.
As there can be several portal container instances per JVM, it is important to be able to configure the loaded services per instance. Therefore, all the default configuration files located in the service implementation jar can be overridden from the portal war. For more information, refer to Service configuration for beginners.
After deploying, you will find the configuration.xml
file in
webapps/portal/WEB-INF/conf
. Use component registration tags.
Let's look at the key tag that defines the interface and the type tag that defines the implementation.
Note that the key tag is not mandatory, but it improves performance.
<!-- Portlet container hooks -->
<component>
<key>org.exoplatform.services.portletcontainer.persistence.PortletPreferencesPersister</key>
<type>org.exoplatform.services.portal.impl.PortletPreferencesPersisterImpl</type>
</component>
Register plugins that can act as listeners or external plugin to bundle some plugin classes in other jar modules. The usual example is the Hibernate service to which we can add hbm mapping files even if those are deployed in another Maven artifact.
<external-component-plugins>
<target-component>org.exoplatform.services.database.HibernateService</target-component>
<component-plugin>
<name>add.hibernate.mapping</name>
<set-method>addPlugin</set-method>
<type>org.exoplatform.services.database.impl.AddHibernateMappingPlugin</type>
<init-params>
<values-param>
<name>hibernate.mapping</name>
<value>org/exoplatform/services/portal/impl/PortalConfigData.hbm.xml</value>
<value>org/exoplatform/services/portal/impl/PageData.hbm.xml</value>
<value>org/exoplatform/services/portal/impl/NodeNavigationData.hbm.xml</value>
</values-param>
</init-params>
</component-plugin>
</external-component-plugins>
In that sample, we target the HibernateService and we will call its
addPlugin()
method with an argument of the AddHibernateMappingPlugin type.
That object will first be filled with the init parameters.
Therefore, it is possible to define services that will be able to receive plugins without implementing any framework interface.
Another example of use is the case of listeners as in the following code where a listener is added to the OrganisationService and will be called each time a new user is created:
<external-component-plugins>
<target-component>org.exoplatform.services.organization.OrganizationService</target-component>
<component-plugin>
<name>portal.new.user.event.listener</name>
<set-method>addListenerPlugin</set-method>
<type>org.exoplatform.services.portal.impl.PortalUserEventListenerImpl</type>
<description>this listener create the portal configuration for the new user</description>
<init-params>
<object-param>
<name>configuration</name>
<description>description</description>
<object type="org.exoplatform.services.portal.impl.NewPortalConfig">
<field name="predefinedUser">
<collection type="java.util.HashSet">
<value><string>admin</string></value>
<value><string>exo</string></value>
<value><string>company</string></value>
<value><string>community</string></value>
<value><string>portal</string></value>
<value><string>exotest</string></value>
</collection>
</field>
<field name="templateUser"><string>template</string></field>
<field name="templateLocation"><string>war:/conf/users</string></field>
</object>
</object-param>
</init-params>
</component-plugin>
...
In the previous XML configuration, we refer to the organization service and we will call its method, that is addListenerPlugin with an object of PortalUserEventListenerImpl type. Each time a new user will be created (apart from the predefined ones in the list above), methods of the PortalUserEventListenerImpl will be called by the service.
As you can see, there are several types of init parameters, from a simple value param which binds a key with a value to a more complex object mapping that fills a JavaBean with the info defined in the XML.
There are many other examples, such as the Scheduler Service where
you can add a job with a simple XML configuration, or the JCR Service where
you can add a NodeType from your own configuration.xml
file.
When the RootContainer is starting, it looks
for configuration files in each jar available from the classpath at jar
path: /conf/portal/configuration.xml
and from each war at path:
/WEB-INF/conf/configuration.xml
. These configurations are added to a set.
If a component is configured in a previous jar and the current jar
contains a new configuration of that component, the latest (from the
current jar) will replace the previous configuration.
After the search of all configurations available on the system, the container will initialize the configuration set and start each component in order of the dependency injection (DI).
So, in general, the user/developer should be careful when configuring the same components in different configuration files. It is recommended to configure a service in its own jar only. Or, in case of a portal configuration, strictly reconfigure the component in portal files.
But, there are components that can be (or should be) configured more than one time. This depends on the business logic of the component. A component may initialize the same resource (shared with other players) or may add a particular object to a set of objects (shared with other players too). In the first case, it is critical who will be the last, for example, whose configuration will be used. In the second case, it does not matter who is the first and who is the last (if the parameter objects are independent).
To debug problems with configuration of components, it is important to know from which jar/war the problem comes. For that purpose, as a user or developer, you can set JVM system property org.exoplatform.container.configuration.debug, in the command line:
java -Dorg.exoplatform.container.configuration.debug ...
With this property, the container configuration manager will report configuration adding process to the standard output (System.out) like this:
... Add configuration jar:file:/D:/Projects/eXo/dev/exo-working/exo-tomcat/lib/exo.kernel.container-trunk.jar!/conf/portal/configuration.xml Add configuration jar:file:/D:/Projects/eXo/dev/exo-working/exo-tomcat/lib/exo.kernel.component.cache-trunk.jar!/conf/portal/configuration.xml Add configuration jndi:/localhost/portal/WEB-INF/conf/configuration.xml import jndi:/localhost/portal/WEB-INF/conf/common/common-configuration.xml import jndi:/localhost/portal/WEB-INF/conf/database/database-configuration.xml import jndi:/localhost/portal/WEB-INF/conf/ecm/jcr-component-plugins-configuration.xml import jndi:/localhost/portal/WEB-INF/conf/jcr/jcr-configuration.xml ...