Assumption
It is assumed that you are working for a publishing company called "La Verdad" that is going to use eXo Platform, and your boss asks you to calculate the number of sentences in an article.
Remember that everything is a service in eXo Platform, so you decide to create a simple class. You want to be able to plug different implementations of your service in the future, so you define an interface that defines your service.
package com.laverdad.services;
public interface ArticleStatsService {
public abstract int calcSentences(String article);
}
A very simple implementation:
public class ArticleStatsServiceImpl implements ArticleStatsService {
public int calcSentences(String article) {
throw new RuntimeException("Not implemented");
}
}
That's all! As you see, no special prerequisite is required for a service.
You should already have prepared your working environment, where
you have a base folder (let's call it our service base folder).
If you wish to try out this example, create this class in the com/laverdad/services/ArticleStatsService
subfolder.
When creating a service, you also should declare its existence to
the Container, therefore you create a
first simple configuration file. Copy the following code to a file
called configuration.xml
and place this file in a /conf
subdirectory
of your service base folder. As you already know the container looks for a /conf/configuration.xml
file in each .jar
package.
<?xml version="1.0" encoding="UTF8"?>
<configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"
xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd">
<component>
<key>com.laverdad.services.ArticleStatsService</key>
<type>com.laverdad.services.ArticleStatsServiceImpl</type>
</component>
</configuration>
You are correctly using the namespace of the configuration
schema (http://www.exoplatform.org/xml/ns/kernel_1_2.xsd
).
Most of the configuration schema is explained in this article,
therefore you do not need to open and understand the schema.
For backward compatibility, it is not necessary to declare the schema.
When eXo kernel reads a configuration, it loads the file from the kernel jar using the classloader and does not use an internet connection to resolve the file.
You see your service has a configuration file, but you wonder how the service can gain access to its configuration. Imagine that you are asked to implement two different calculation methods: fast and exact.
You create one init parameter containing the calculation methods. For the exact method, you wish to configure more details for the service. Let's enhance the word service configuration file:
<component>
<key>com.laverdad.services.ArticleStatsService</key>
<type>com.laverdad.services.ArticleStatsServiceImpl</type>
<init-params>
<value-param>
<name>calc-method</name>
<description>calculation method: fast, exact</description>
<value>fast</value>
</value-param>
<properties-param>
<name>details-for-exact-method</name>
<description>details for exact phrase counting</description>
<property name="language" value="English" />
<property name="variant" value="us" />
</properties-param>
</init-params>
</component>
When configuring your service, you are totally free. You can provide as many value-param, property-param, and properties as you wish, and you can give them any names or values. You only must respect the xml structure.
Now let's see how our service can read this configuration.
The implementation of the calcSentences()
method serves just as a simple example.
It's up to your imagination to implement the exact method.
public class ArticleStatsServiceImpl implements ArticleStatsService {
private String calcMethod = "fast";
private String variant = "French";
private String language = "France";
public ArticleStatsServiceImpl(InitParams initParams) {
super();
calcMethod = initParams.getValueParam("calc-method").getValue();
PropertiesParam detailsForExactMethod = initParams.getPropertiesParam("details-for-exact-method");
if ( detailsForExactMethod != null) {
language = detailsForExactMethod.getProperty("language");
variant = detailsForExactMethod.getProperty("variant");
}
}
public int calcSentences(String article) {
if (calcMethod == "fast") {
// just count the number of periods "."
int res = 0;
int period = article.indexOf('.');
while (period != -1) {
res++;
article = article.substring(period+1);
period = article.indexOf('.');
}
return res;
}
throw new RuntimeException("Not implemented");
}
}
You see you just have to declare a parameter of org.exoplatform.container.xml.InitParams in your constructor. The container provides an InitParams object corresponding to the xml tree of init-param.
As you want to follow the principle of Inversion of Control, you must not access the service directly. You need a Container to access the service.
With this command, you get your current container:
ExoContainer myContainer = ExoContainerContext.getCurrentContainer();
Whenever you need one of the services that you have configured, use the method:
myContainer.getComponentInstance(class)
In our case:
ArticleStatsService statsService = (ArticleStatsService) myContainer.getComponentInstance(ArticleStatsService.class);
Recapitulation:
package com.laverdad.common;
import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.ExoContainerContext;
import com.laverdad.services.*;
public class Statistics {
public int makeStatistics(String articleText) {
ExoContainer myContainer = ExoContainerContext.getCurrentContainer();
ArticleStatsService statsService = (ArticleStatsService)
myContainer.getComponentInstance(ArticleStatsService.class);
int numberOfSentences = statsService.calcSentences(articleText);
return numberOfSentences;
}
public static void main( String args[]) {
Statistics stats = new Statistics();
String newText = "This is a normal text. The method only counts the number of periods. "
+ "You can implement your own implementation with a more exact counting. "
+ "Let`s make a last sentence.";
System.out.println("Number of sentences: " + stats.makeStatistics(newText));
}
}