Demystifying Custom Adapter Development: Part 2 – Examining the Adapter’s Key Classes and Methods
In the previous part of this custom adapter development series, we have walked through the steps to clone the sample JCA adapter and deploy it into the PI system.
In this part, we will be having a closer look at the Java source codes that form the custom adapter. We will only be looking at some of the key classes and their methods, in order to have a better understanding on the behavior of the adapter during the different stages in its life cycle.
This part will be a bit “drier” compared to the previous part as it will not have as much hands-on steps. However, it is crucial to have an understanding of these key elements as the basis for subsequent modification of the adapter according to specific requirements.
Deployment and Adapter Registration
During deployment of the adapter, it will perform registration of itself with the adapter framework. Following are some of the key aspects of the registration process.
SPIManagedConnectionFactory (SMCF) is one of the central classes for the adapter. Below are the description of the class as taken from the comments section of the class:-
An object of the class SPIManagedConnectionFactory (MCF) is a factory of both,
ManagedConnection and CCIConnectionFactory instances.
This class supports connection pooling by defining methods for matching and creating connections.
When an object of SMCF is created, it will perform a JNDI Lookup to retrieve an object of SAPAdapterResources.
Subsequently, SMCF is started by the AS Java server which calls its start() method. This in turn calls the startMCF() method. Within the startMCF() method, the above SAPAdapterResources object will execute its startRunnable() method using the SMCF object as a reference. This is to enable the SMCF to run in its own thread which is used to handle inbound processing.
As SMCF implements the Runnable interface, its run() method will subsequently be executed in its on thread.
Within the run() method, the adapter type and namespace are set. As mentioned in the first part of the series, it is important that the combination of the type and namespace forms a unique pair as this combination will be used during the registration of the adapter. This unique pair also has to match the name used for the Adapter Metadata in ESR.
The above combination is used as input values during construction of an XIConfiguration object. This class manages all the channel information.
Within the init() method of the XIConfiguration object, an execution of the registerAdapter() method of AdapterRegistry is performed to register the adapter with the adapter framework.
Successful registration of the adapter with the framework is crucial to ensure proper behavior and processing of the associated channels.
If the registration was not successful, channels created for this adapter will have the error “No adapter registered for this channel” when viewed in the Communication Channel Monitor.
Side Note: Although the SMCF class implements the Runnable interface, it is not mandatory for it to do so. Implementation of the Runnable interface (to handle threads for inbound processing) can be delegated to a separate/new class as long as an object of the class is passed as an input value to the startRunnable() method.
During the lifecycle of a deployed adapter, channels can be created, changed and deleted for the adapter type. The XIConfiguration class is responsible for managing the details of channels for an adapter.
Following are some of the methods executed when actions for channels of an adapter are taken.
Following is an example of the one of the methods, channelAdded().
The class maintains private attributes that contain lists of both inbound (sender) and outbound (receiver) channels that belongs to the adapter.
During the execution of the method, the newly created channel will be added to the list. Note that this logic is executed within a synchronized block to ensure that the contents of the list is consistent in multi-threaded executions.
Following are some of the key aspects during runtime execution of channels for the adapter.
A) Receiver Channel Processing
For receiver channel processing, the message is processed by the execute() method of class CCIInteraction. Within this method, it determines whether it is an asynchronous (Send) or synchronous (Call) execution and calls the corresponding method accordingly.
As an example, for an asynchronous message, the send() method is called. In the sample JCA adapter, it will create an output file (according to the directory and filename configured in the receiver channel) in the file system of the PI server.
The following logic section in the method constructs the target output file.
An below is an example output generated by a sample message processed by the receiver JCA adapter.
B) Sender Channel Processing
The sample JCA adapter provides a polling mechanism for the sender channel to poll files from the file system of the PI server.
The logic is implemented within the run() method of the SPIManagedConnectionFactory class.
After the wait time is completed for each polling interval, method sendMessageFromFile() is executed to pick up file(s) from the configured directory and generate an message in the Messaging System.
Refactoring Hard-coded Adapter Constant Values
Now that we have examined some of the key aspects of the adapter logic, we will have some hands-on to prepare the adapter project for modifications that will be introduced in the later parts of this series.
The source code for the sample JCA adapter contains many hard-coded values across the different classes. In this section, we will consolidate all these hard-coded values in a separate class as static final attributes. This is an optional yet recommended step in order to allow for ease of change in the future.
Below is the new class AdapterConstants that contains these constant values. Subsequently, the various classes are updated to reference these constants instead of hard-coding them within the classes themselves.
Phew! Finally, we have come to the end of this part and hopefully gained a better understanding on some of the internal behavior of the custom adapter. This will provide the foundation needed when we introduce modifications to the adapter later on in this series. In the next post, we will be looking at the deployment descriptor, manifest and adapter metadata files.
Other Parts of this Series