Component Common Library

The Component Common Library is a collection of classes that facilitate the development of new components. It contains abstract component classes allowing to quickly create new jbi component instances. It also contains some helpers allowing to manipulate wsdl files or jbi message contents. All the PEtALS components use the new PEtALS component commons (exception : CSV and XquareBC).

This component development kit (also named PEtALS CDK) can be used to create components than will run on other JBI containers.

All these classes are available in the "petals-component-common.jar".

Here is the javadoc : ComponentCommonAPI-Javadoc.zip

Component commons architecture

cdk.png

How to create a simple Service Engine

AbstractServiceEngine

To create a simple service engine component you must extend org.objectweb.petals.component.common.se.AbstractServiceEngine abstract class. Then you just have to implement the following abstract method :

protected abstract boolean onExchange(MessageExchangeWrapper exchange,
Extensions extensions) throws HandlingException;
All business logic is delegated to those method. Note that the default behaviour of this component is to ignore all messages whom status is "ERROR" or "DONE". Description of the parameters :
  • exchange : a wrapper of the message exchange to process. It can't be null. It handles all message exchange information (operation, targeted endpoint...). The wrapper add some util methods to easily retrieve message exchange information like embedded normalized messages...
  • extensions : JBI descriptor extensions. The message exchange targets a specific endpoint, this endpoint has been activated during the processing of a provides node of a service unit jbi descriptor. These extensions are the extensions of this provides node. They can be null.
The returned boolean is used in case of "InOptionalOut" pattern. It must be true if there's an out message, false otherwise.

ServiceEngineServiceUnitManager

This component also creates a org.objectweb.petals.component.common.se.ServiceEngineServiceUnitManager during its initialization process. This manager simply activates new endpoints described in the "services"/"provides" nodes of deployed service units descriptor (jbi.xml), and map abstract addresses to existing endpoint with "services"/"consumes" nodes.

There's no required pattern for abstract addresses specified in "consumes" node. So the developper is in charge of validating and processing addresses in his component. We recommand to use valid URI addresses but it isn't a requirement.

For more information about service unit deployment descriptor (jbi.xml) see the section below : Service Assembly and Service Unit.

How to create a simple binding component

AbstractBindingComponent

To create a new Binding Component, extends the "org.objectweb.petals.component.common.bc.AbstractBindingCompnent". class The method :

protected void init(BindingComponentInitializer initializer);

must be defined to initialize JBIListener and ExternalListenerManager handled by the BindingComponentInitializer.

The abstract component framework calls this method after the component initialization so delivery channel, context, logger and service unit manager are available.

If your binding component has to handle JBI MessageExchanges, set the jbiListener attribute on the initializer parameter with your own implementation of JBIListener interface.

If your binding component has to handle messages from external service and sends them to the JBI environment, internal jbi components, set the externalListenerManager attribute on the initializer parameter with your own implementation of ExternalListenerManager interface.

JBIListener

The JBIListener will send an incoming JBI message to an outside service.

To create your own JBIListener, you just have to implement the following method of the JBIListener interface :

public boolean onJBIMessage(String address, MessageExchangeWrapper exchange, Extensions extensions)
throws MessagingException;

This method will be called when a new MessageExchange reaches your Binding Component. It sends an incoming JBI message to an outside service. The address associated with the requested endpoint is resolved by the abstract component. Description of the parameters :

  • address : the external service address associated to the endpoint given in the incoming MessageExchange
  • exchange : the message exchange to process. Not null
  • extensions : JBI descriptor extensions. The message exchange targets a specific endpoint, this endpoint has been activated during the processing of a provides node of a service unit jbi descriptor. Theses extensions are the extensions of this provides node. It can be null.
The returned boolean is used in case of "InOptionalOut" pattern. It must be true if there's an out message, false otherwise.
ExternalListenerManager

The ExternalListenerManager is used to enable a binding component to handle external service calls. It defines methods to register and unregister listeners for external services. Registered listeners listen to incoming messages from external services, in order to forward these messages to internal JBI Components.

To create your own ExternalListenerManager, you just have to implement the following methods :

public void startListening(String address) throws Exception;

public void stopListening(String address);

The first one will be called when the ServiceUnitManager will start a service unit containing a "consumes" node in its descriptor. It must launch a listener for the given external address. This listener will forward external calls to internal JBI components. The component developper is in charge of creating and starting listeners for each time the startListening method is called.

The second one will be called when the ServiceUnitManager will stop a service unit containing a "consumes" node in its descriptor. It must stop the previously started listener for the given address.

BindingComponentServiceUnitManager

The BindingComponentServiceUnitManager does the same as the ServiceEngineServiceUnitManager but it adds external listener manipulation : during the starting process of a service unit it call the "startListening" method of the ExternalListenerManager for each "consumes" node of the jbi.xml file of the service unit; during the stopping process of a service unit it call the "stopListening" method of the ExternalListenerManager for each "consumes" node of the jbi.xml file of the service unit.

For more information about service unit deployment descriptor (jbi.xml) see the section below : Service Assembly and Service Unit.

ServiceUnitListener

If your component needs extra processing on ServiceUnit deployment or start, set on your component, during the init(initializer) call, the serviceUnitListener object (with the setServiceUnitListener() method).

A service unit listener implements the org.objectweb.petals.component.common.su.ServiceUnitListener interface.

This listener is called after service units deployment, start, stop and undeployment.

public interface ServiceUnitListener {
    void onSUDeployed(String serviceUnitName, String suRootPath,
        JBIDescriptor descriptor) throws PEtALSComponentSDKException;

void onSUStarted(String serviceUnitName) throws PEtALSComponentSDKException;

void onSUStopped(String serviceUnitName) throws PEtALSComponentSDKException;

void onSUUndeployed(String serviceUnitName, String suRootPath, JBIDescriptor descriptor) throws PEtALSComponentSDKException; }

ServiceUnitExtensionsValidator

If your component needs to validate the SU extensions (provides and consumes ones), you can set a custom ServiceUnitExtensionsValidator during the component init(initializer) method. Call the setServiceUnitExtensionsValidator().

A ServiceUnitExtensionsValidator implements the org.objectweb.petals.component.common.su.ServiceUnitExtensionsValidator interface.

public interface ServiceUnitExtensionsValidator {
   void validateConsumesExtensions(Extensions extensions)
            throws PEtALSComponentSDKException;

void validateProvidesExtensions(Extensions extensions) throws PEtALSComponentSDKException; }

If an exception is throwed by these methods, the complete SU will not be deployed.

In general, such a feature is used when some extensions are required by the component. If the extension value is missing, the component will not be abble to run correctly.

Component Bootstrap

JBI specification allows developer to customize the component installation process. To do it, developer must implement the javax.jbi.component.Bootstrap interface.

The CDK provides :

  • A standard implementation of this interface with the org.objectweb.petals.component.common.SimpleBootstrap class. All implemented methods do nothing. It can be used as default bootstrap class.
  • An advanced implementation which allows component configuration through JMX

Simple bootstrap

This bootstrap does nothing special.

Managed Bootstrap

The ManagedBootstrap class extends the SimpleBootstrap one. With the managed bootstrap, you can expose properties and methods for management during the bootstrap phase.
To expose attributes and methods, you must extend the ManagedBootstrap class and override the method :
doComponentConfiguration(Map<String, String> componentAttributes, List<String> methods)
  • In the method body, you can add attributes for management like this :
methods.add("methodToExpose");

The method 'methodToExpose' can be called during bootstrap through JMX. Sample of an exposed method : jmx-method.png

  • In the method body, you can expose methods for management like this :
componentAttributes.putAll(Map<String, String> map);

All the attributes will be accessible during bootstrap through JMX. Sample of exposed attributes : jmx-attr.png

Service assembly and service unit

Service assemblies are set of service units. Each service unit must include a JBI descriptor "jbi.xml" file and may include a service descriptions as ".wsdl" files. The service unit descriptor file (jbi.xml) is composed of "provides" and "consumes" nodes.

The provides node

The "provides" node is used when you want to register in the JBI container an endpoint for external services. When deploying a service unit, information contained in the provides node is used to activate a new endpoint in JBI environment. An endpoint with the "endpoint-name", "service-name" and "interface-name" is activated.

If the provides node is used by a binding component to activate a new endpoint in JBI environment, a Petals extensions must be added to the provides node to linked the newly activated component to an external address. Here is an exemple of a provides node activating a new endpoint and linking it to an external Email address :

<jbi version="1.0" xmlns='http://java.sun.com/xml/ns/jbi'
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xmlns:petals="http://petals.objectweb.org/"
	xmlns:extensions="http://petals.objectweb.org/extensions/"
	xmlns:keyvalue="http://petals.objectweb.org/extensions/key-value/">
  <services binding-component="true">
    <provides interface-name="SendMail"
	service-name="petals:SendMailService"
	endpoint-name="SendMailEndpoint">
	<extensions:extensions>
		<keyvalue:extension>
    <address>smtp://ofabre@www.ebmwebsourcing.org/to:olivier.fabre@ebmwebsourcing.com/from:olivier.fabre@enstimac.fr</address>
		</keyvalue:extension>
	</extensions:extensions>
    </provides>
  </services>
</jbi>
Additional extensions
<wsdl>
Has an extension you can also add the wsdl entry to give the WSDL URL of the service like this:

<keyvalue:extension>
  <address>...</address><wsdl>http://petals.objectweb.org/services/myservice?wsdl</wsdl>
</keyvalue:extension>

Supported URL protocols are http, https and file ones. You can also provide the path to the WSDL file has a relative address from the deployed SU (like ../../mywsdlfile.wsdl for example).

The consumes node

The consumes node is used when you want to make available to outside consumers, services from the JBI container. When deploying a service unit, information contained in the consumes node is used to associate the distant service address (the one outside consumer will call to reach JBI services) and the endpoint of the JBI service you want to expose. Here is an exemple of a consumes node mapping an external imap address to an internal jbi endpoint (HelloworldEndpoint) :

<jbi version="1.0" xmlns='http://java.sun.com/xml/ns/jbi'
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xmlns:petals="http://petals.objectweb.org/"
	xmlns:extensions="http://petals.objectweb.org/extensions/"
	xmlns:keyvalue="http://petals.objectweb.org/extensions/key-value/">
  <services binding-component="true">
	<consumes interface-name="Helloworld"
		service-name="petals:HelloworldService"
		endpoint-name="HelloworldEndpoint">
		<extensions:extensions>
			<keyvalue:extension>
				<address>imap://mailbc@www.ebmwebsourcing.org</address>
			</keyvalue:extension>
		</extensions:extensions>
	</consumes>
  </services>
</jbi>

Petals Extensions

As you can see in code snippets above, Petals provides JBI Extensions management. Petals extensions have structure as follow :

<extensions:extensions>
	<keyvalue:extension>
		<address>imap://mailbc@www.ebmwebsourcing.org</address>
	</keyvalue:extension>
</extensions:extensions>

Petals extensions are bundled into a tag with the following namespace : "http://petals.objectweb.org/extensions/". Each Petals extension type is identified by its namespace. For the moment, only one extension type is provided by the Petals container : the key-value extension. Those extension has the following namespace : "http://petals.objectweb.org/extensions/key-value/". All nodes included in the key-value entension node are mapped to an hashmap with the following pattern :

<key>value</key> mapped to key --> value in the map

All extensible elements (as described in the jbi xml schema of the jbi specification) can use Petals extensions or your custom extensions. Custom extensions aren't processed by Petals container and they will be provided to jbi developper as javax.xml.Document.

Thread pool configuration
All components based on the CDK contain a thread pool to process requests. The thread pool is configured through the following Petals extensions in the JBI descriptor of the component (binding-component or service-engine):
<extensions:extensions>
	<keyvalue:extension>
		<queueSize>50</queueSize>
		<corePoolSize>10</corePoolSize>
		<maxPoolSize>15</maxPoolSize>
		<keepAliveTime>600</keepAliveTime>
	</keyvalue:extension>
</extensions:extensions>
  • queueSize: The size of the queue to use for holding tasks before they are executed. Default value is 50.
  • corePoolSize: The number of threads to keep in the pool, even if they are idle. Default value is 10.
  • maxPoolSize: The maximum number of threads to allow in the pool. Default value is 50.
  • keepAliveTime: When the number of threads is greater than the core, this is the maximum time (in seconds) that excess idle threads will wait for new tasks before terminating. Default value is 600.

Logging in the component

As a JBI container, PEtALS can deliver loggers to a component. In order to ease the logging in a component, you can use the ComponentLogger (package org.objectweb.petals.component.common.util) to log your messages. They will be automatically prefixed with the name of the component.