JBoss.orgCommunity Documentation

Chapter 54. Service Configuration for Beginners

54.1. Objective
54.2. Requirements
54.3. Services
54.4. Configuration File
54.5. Execution Modes
54.6. Containers
54.7. Configuration Retrieval
54.7.1. RootContainer
54.7.2. PortalContainer
54.7.3. StandaloneContainer
54.8. Service instantiation
54.9. Miscellaneous
54.9.1. Startable interface
54.9.2. Inversion of Control
54.9.3. More Containers
54.9.4. Single Implementation Services
54.9.5. Configuration properties
54.9.6. Configuration Logging
54.10. Further Reading

Related documents

We are going to talk about service configuration. You will learn about modes, services and containers, you will find out where the service configuration files have to be placed and you will also see the overriding mechanism of configurations. Finally you will understand how the container creates the services one after the other and what Inversion of Control really means.

By reading this article you are already glancing at the heart of eXo Kernel.

Even you will read in this article to open the directory "exo-tomcat", you may have installed eXo Portal on any application server, just replace "exo-tomcat" by your folder name.

You certainly already discovered eXo's fisheye URL (eXo is open source!) - https://anonsvn.jboss.org/repos/exo-jcr/ - which allows you to surf in the source code of all classes, if you wish to do so.

Nearly everything could be considered a service! To get a better idea, let's look into the exo-tomcat/lib folder where you find all deployed jar files.

For example you find services for databases, caching, ldap and ftp:

Of course, there are many more services, in fact a lot of these jar files are services. To find out you have to open the jar file and then look into its /conf or /conf/portal directory. Only if there is a file named configuration.xml, you are sure to have found a service.

Interface - Implementation It's important to get the idea that you separate the interface and implementation for a service. That is a good concept to reduce dependencies on specific implementations. This concept is well known for JDBC. If you use standard JDBC (=interface), you can connect any database (=implementation) to your application. In a similar way any service in eXo is defined by a java interface and may have many different implementations. The service implementation is then injected by a container into the application.

Singleton Each service has to be implemented as a singleton, which means that each service is created only once - in one single instance.

Service = Component You always read about services, and you imagine a service as a large application which does big things, but that's not true, a service can be just a little component that reads or transforms a document, therefore the term component is often used instead of service - so bear in mind: a service and a component can safely be considered to be the same thing.

The jar file of a service should contain a default configuration, you find this configuration in the configuration.xml file which comes with the jar. A configuration file can specify several services, as well as there can be several services in one jar file.

For example open the exo.kernel.component.cache-2.0.5.jar file and inside this jar open /conf/portal/configuration.xml. You will see:

 
<component>
<key>org.exoplatform.services.cache.CacheService</key> 
<type>org.exoplatform.services.cache.impl.CacheServiceImpl</type> 
...

Here you will note that a service is specified between the <component> tags. Each service has got a key, which defines the kind of service. As you imagine the content of the <key> tag matches the qualified java interface name (org.exoplatform.services.cache.CacheService) of the service. The specific implementation class of the CacheService is defined in the <type> tag.

Parameters You have already opened some configuration files and seen that there are more than just <key> and <type> tags. You can provide your service with init parameters. The parameters can be simple parameters, properties, or object-params. There are also plugins and they are special because the container calls the setters of your service in order to inject your plugin in your service (called setter injection) see Service Configuration in Detail. In general your service is free to use init parameters, they are not required.

If you ever need to create your own service, the minimum is to create an empty interface, an empty class and a constructor for your class - that's all. Ok, you also should put your class and the interface in a jar file and add a default configuration file.

One important thing to understand concerns execution modes. There are only two modes:

In order to access to a service you need to use a Container. Just open https://anonsvn.jboss.org/repos/exo-jcr/kernel/trunk/exo.kernel.container/src/main/java/org/exoplatform/container.

Among the classes you see in this directory, you only will be interested in these three container types:

  • RootContainer: This is a base container. This container plays an important role during startup, but you should not use it directly.

  • PortalContainer: Created at the startup of the portal web application (in the init() method of the PortalController servlet)

  • StandaloneContainer: A context independent eXo Container. The StandaloneContainer is also used for unit tests.

Use only one container Even if there are several container types you always use exactly one. The RootContainer is never directly used and it depends on the execution mode if you use the PortalContainer or the StandaloneContainer. You will ask how to find out the execution mode in my application and how to manage these two modes. It's easy, you don't have to worry about it because the ExoContainerContext class provides a static method that allows you to get the right container from anywhere (see info box).

PicoContainer All containers inherit from the ExoContainer class which itself inherits from a PicoContainer. PicoContainer is a framework which allows eXo to apply the IoC (Inversion of Control) principles. The precise implementations of any service is unknown at compile time. Various implementations can be used, eXo supplies different implementations but they also may be delivered by other vendors. The decision which service to use during runtime is made in configuration files.

These configuration files are read by the container, the container adds all services to a list or more exactly a java HashTable. It's completely correct to suppose that the configuration.xml you already saw plays an important role. But there are more places where a configuration for a service can be defined as you see in the next chapter.

Note

"In your java code you have to use

ExoContainer myContainer = ExoContainerContext.getCurrentContainer();

in order to access to the current container. It doesn't greatly matter to your application if the current container is a PortalContainer or a StandaloneContainer. Once you have your container you may access to any service registered in this container using

MyService myService = (MyService) myContainer.getComponentInstance(MyService.class);

You easily realize that MyService.class is the name of the service interface.

The configuration you find inside the jar file is considered as the default configuration. If you want to override this default configuration you can do it in different places outside the jar. When the container finds several configurations for the same service, the configuration which is found later replaces completely the one found previously. Let's call this the configuration override mechanism.

As both containers, PortalContainer and StandaloneContainer, depend on the RootContainer, we will start by looking into this one.

The retrieval sequence in short:

HashTable The RootContainer creates a java HashTable which contains key-value pairs for the services. The qualified interface name of each service is used as key for the hashtable. Hopefully you still remember that the <key> tag of the configuration file contains the interface name? The value of each hashtable pair is an object that contains the service configuration (yes, this means the whole structure between the <component> tags of your configuration.xml file).

The RootContainer runs over all jar files you find in exo-tomcat/lib and looks if there is a configuration file at /conf/configuration.xml, the services configured in this file are added to the hashtable. That way - at the end of this process - the default configurations for all services are stored in the hashtable.

If you wish to provide your own configurations for one or several services, you can do it in a general configuration file that has to be placed at exo-tomcat/exo-conf/configuration.xml. Do not search for such a file on your computer - you won't find one, because this option is not used in the default installation. Here again the same rule applies: The posterior configuration replaces the previous one.

The further configuration retrieval depends on the container type.

The PortalContainer takes the hashtable filled by the RootContainer and continues to look in some more places. Here you get the opportunity to replace RootContainer configurations by those which are specific to your portal. Again, the configurations are overridden whenever necessary.

In short PortalContainer configurations are retrieved in the following lookup sequence :

You see, here the /conf/portal/configuration.xml file of each jar enters the game, they are searched at first. Next, there is nearly always a configuration.xml in the portal.war file (or in the portal webapp folder), you find this file at /WEB-INF/conf/configuration.xml. If you open it, you will find a lot of import statements that point to other configuration files in the same portal.war (or portal webapp).

Multiple Portals Be aware that you might set up several different portals ("admin", "mexico", etc.), and each of these portals will use a different PortalContainer. And each of these PortalContainers can be configured separately. As of eXo Portal 2.5 you also will be able to provide configurations from outside the jars and wars or webapps. Put a configuration file in exo-tomcat/exo-conf/portal/$portal_name/configuration.xml where $portal_name is the name of the portal you want to configure for . But normally you only have one portal which is called "portal" so you use exo-tomcat/exo-conf/portal/portal/configuration.xml.

In the same way as the PortalContainer the StandaloneContainer takes over the configuration of the RootContainer. After that our configuration gets a little bit more tricky because standalone containers can be initialized using an URL. This URL contains a link to an external configuration. As you probably never need a standalone configuration you can safely jump over the remaining confusing words of this chapter.

After taking over RootContainer's configuration, there are three cases which depend on the URL initialization, :

As you have already learned the services are all singletons, so that the container creates only one single instance of each container. The services are created by calling the constructors (called constructor injection). If there are only zero-arguments constructors (Foo public Foo(){}) there are no problems to be expected. That's easy.

But now look at https://anonsvn.jboss.org/repos/exo-jcr/core/trunk/exo.core.component.organization.jdbc/src/main/java/org/exoplatform/services/organization/jdbc/OrganizationServiceImpl.java

This JDBC implementation of BaseOrganizationService interface has only one constructor:

public OrganizationServiceImpl(ListenerService listenerService, DatabaseService dbService);

You see this service depends on two other services. In order to be able to call this constructor the container first needs a ListenerService and a DatabaseService. Therefore these services must be instantiated before BaseOrganizationService, because BaseOrganizationService depends on them.

For this purpose the container first looks at the constructors of all services and creates a matrix of service dependencies in order to call the services in a proper order. If for any reason there are interdependencies or circular dependencies you will get a java Exception. In this way the dependencies are injected by the container.

Note

What happens if one service has more than one constructor? The container always tries first to use the constructor with a maximum of arguments, if this is not possible the container continues step by step with constructors that have less arguments until arriving at the zero-argument constructor (if there is one).

Retrospection Do you remember your last project where you had some small components and several larger services? How was this organized? Some services had their own configuration files, others had static values in the source code. Most components were probably tightly coupled to the main application, or you called static methods whenever you needed a service in your java class. Presumably you even copied the source code of an earlier project in order to adapt the implementation to your needs. In short:

New Approach You have seen that eXo uses the Inversion of Control (IoC) pattern which means that the control of the services is given to an independent outside entity, in this case a container. Now the container takes care of everything:

Dependency Injection You also saw two types of dependency injections:

Do you feel an expert now? Not yet. Get a deeper look and read this Services Wiring article. You read so much about configuration, that you should wonder what the XML Schema of the configuration file looks like.

If you wish to see a examples of service configurations you should study the Core. Where you find descriptions of some eXo's core services. Finally you might wish to read more about PicoContainer.