The previous section introduced how you could concretely make a Petals component.
|
Table of contents Contributors
No contributors found for: authors on selected page(s)
|
BC vs. SE
As explained in the introduction, there are two kinds of Petals components.
A Petals component is either a binding component, or a service engine.
Binding components (BC) are links between the services in the bus and external applications.
The natural way to provide these bounds is the usage of communications protocols. This is why binding components are generally associated with communication protocols, like SOAP, RMI, JMS...
Service engines (SE) are pieces of application logics fully integrated in the bus.
They are exposed directly as services into the bus. It can be executing code (POJO), performing transformations (XSLT), scheduling (Quartz) and so on...
However, most of the components do nothing by themselves if they are alone.
They provide integration in the bus, and features to use. These features can only be used by artifacts called service-units.
We could say service-units are component configurations, but that would be ambiguous, as a stand-alone component also has configurations files.
Service units
In fact, service-units should be seen as configuration artifacts.
A service-unit is a zip archive, with a specific structure, and which contains files and resources. A service-unit targets one and only one component. The resources it holds are used by the component to create, or emulate, a service in the bus.
A service-unit contains a jbi.xml file, which define services to expose or services to invoke (consume) in the bus. A service is exposed by a triplet, made up of an interface name (which is a qualified name), a service name (also a qualified name) and an end-point name. In case of a service provider, a WSDL definition should be referenced too. In that case, the triplet values must match the properties of the WSDL file.
The other resources are used by the component with respect to its logic.
As an example, a service-unit for the XSLT service-engine must contain a XSL file. This file is used by the component to run XSL transformations, the transformation being based on this XSL sheet.
A service-unit embeds:
- A JBI descriptor (META-INF/jbi.xml file), which defines the provided and consumed services.
Each service is described with an interface name, a service name, an end-point name, plus additional parameters. The JBI descriptor is what was called “service-unit configuration”. - A WSDL file, which is the interface of the service created by the component from this configuration. It is referenced in the JBI descriptor.
- Depending on the component task, some other resources (e.g. Java code), directly or indirectly referenced by the JBI descriptor (Java libraries are indirectly referenced through a class name).
The provided WSDL is the interface of the service that will be created by the component from the configuration. Every service in Petals should have a WSDL interface, so that it can be called (e.g. in an orchestration). In the case where a service-unit does not provide a WSDL, and if it makes sense for your component, your component should provide a default WSDL that can be used for the service-unit.
As an example, this what the Mail and the FTP components offer. The components have generic operations like send(), put(), get() and so on. Therefore, they can provide a WSDL by default. In this case, we speak of native services provided by the component. The configuration then simply provides parameters for these services.
If a service-unit does not embed a WSDL file, and if your component does not have a default one, the Petals kernel generates one by default (setting information from the service-unit jbi.xml file). But this is definitely a situation to avoid, because the generated WSDL has no operation and consequently, cannot be used in WSDL-driven calls.
The CDK
In Petals, components interact with the container according to a standard called JBI (Java Business Integration). This standard defines interfaces that a component must implement to interact with the JBI environment. To simplify the development of these components, Petals provides a framework providing an API which implement the required interfaces and makes the work lighter. This framework, known as the Component Development Toolkit (CDK), also provides utility methods and a common basis for all the Petals components.
Implementing a Petals component based on the CDK reduces the amount of code to write. There are only few interfaces or abstract classes to extend and complete.
When you go through the steps given in the previous pages, the built code relies on the CDK.
One element that must be insisted on, is that the CDK is a framework.
It means you can use the code it provides to develop components quite easily.
But it also requires to be configured. The configuration is made in both the component configuration files, and in the service-unit configurations.
Concretely, it is illustrated by the presence of a CDK section in the JBI descriptors of a component and of a service-unit.
Providers vs. Consumers
In Petals, there are two roles a component can hold.
- A component may act as a provider, which means it provides a service (receives calls).
- Or it may act as a consumer, which means it consumes services (sends calls).
- A component may have both roles.
However, not all the roles may be configured.
Here is a short presentation of some Petals components and their roles:
- The SOAP BC can be a provider.
In this case, the service-units are configured in provides mode.
- The SOAP BC can also act as a consumer.
In this case, the service-units are configured in consumes mode.
For a given service, the SOAP BC is either provider, or consumer. Never both.
- The BPEL SE is able to run BPEL processes. It is both a consumer and a provider. It exposes the BPEL process as a service, but it also calls the services referenced by the BPEL process.
However, the BPEL SE can only be configured in provides mode.
The consumes mode resides in the component implementation, and cannot be configured.
- The EIP SE acts somehow the same way the BPEL SE. It exposes a service, and the implementation of this service calls other services.
The difference with the BPEL SE is in the fact that consumed services are declared in the service-unit configuration. It means the EIP SE can be configured in both provides and consumes mode. Actually, it has to be both at the same time.
The questions you have to think about when creating a component, are whether your component is a service provider, a service consumer, or both, and which roles are explicitly configurable and which ones are implicit. A role is explicitly configurable if the service-unit can configure the role.
Remember, service-units have a JBI descriptor (jbi.xml) file. If this JBI descriptor has a provides section, then the component is configured as a provider for this service. If it has a consumes section, then the component is configured as a consumer for this service. |
If a service-unit declares a section for a role that is not supported by the component, it will not work. Either an error will occur on deployment, or the invalid section will be skipped. The behavior depends on the component implementation, not on the CDK. |
Component's job
A component, in Petals, is responsible for:
- The deployment of a service-unit for this component.
- The management of the resources brought by service-units.
- The reception of messages targeting a service created from one of its service-units.
Hopefully, the deployment part is performed by the CDK (though it can be overridden).
When you create your component, as explained in the first part of this document, the only mandatory work is to complete the generated listeners. These (message) listeners define the behavior of the component when it receives messages.
And this is the point. Messages do not reach directly the services. They are sent to components.
The component receives the messages and must use the service-unit to compute and serve the request. This is also why we could say services are emulated. They completely depend on the component. The advantage of this, however, is to reuse the same basis code for all the services. You do not duplicate or reinvent the wheel when you create a service.
There are two kinds of message listeners to complete:
- JBIListeners listen to messages coming from inside the bus.
When you complete this class, you define the behavior of your component when it is called by another Petals service. Such a listener must be implemented for both a service engine and a binding-component. - ExternalListeners react to external events, that is to say occurring outside the bus.
When you complete this class, you define the way your component handles these events and how they are propagated in Petals. Events can be a file dropped in a directory, or receive an external call through a given protocol.
Only binding components may implement an external listener.
Other classes have a default implementation in the CDK, but can be overridden if necessary.
These classes are discussed in the next pages.
Message dispatching to message listeners
One important thing to know before going deeper about how to handle messages in your component, is the way Petals dispatches messages.
External messages (or events) are not accepted by the bus, but directly handled by the component, in the ExternalListener class.
There is no queue or mechanism provided by the CDK apart the AbstractExternalListener superclass.
Each consumes section in a service-unit configuration results in the creation of an ExternalListener.
For internal messages, that is to say messages coming from the bus, it all relies on the way the kernel dispatches the messages.
For every component based on the CDK, the component JBI descriptor (the jbi.xml file in the component) inherits some fields from the CDK.
<petalsCDK:acceptor-pool-size>5</petalsCDK:acceptor-pool-size> <petalsCDK:processor-pool-size>10</petalsCDK:processor-pool-size>
The acceptor pool size defines the number of threads that can accept messages from the bus in concurrency.
Once a message is accepted by an acceptor, this message is added to a queue, waiting to by processed by a thread from the processor pool.
Since acceptors have few work to do, their number does not have to be high.
The processor pool is in charge of processing the messages added in the waiting queue.
Each thread from the processor pool owns a JBI listener instance.
For every message to process, the processor thread initializes the configuration in the JBI listener instance and calls the onJBIMessage() method.
Messages are picked up by the processor pool in FIFO order.