Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
engswee
Active Contributor

Introduction

Now that we have familiarise ourselves with the various aspects of the custom adapter development, we can proceed with actual changes to modify the adapter's functionality. As an example, we will use the requirement described in the following post and implement the solution using a custom adapter.

Synchronous retrieval of dynamically specified file from file system/server

In summary, we want to synchronously retrieve the contents of a file from the PI file system by providing an input payload containing the full path to the file. This is currently not supported by the File adapter in either sender or receiver mode. To achieve this, we will modify the receiver functionality of the custom adapter to:-

i) Extract from request payload the full path to the file

ii) Extract the file contents

iii) Generate the synchronous response with payload containing the file contents

Adapter Metadata Changes

We will update the SampleRA.xml file which defines the adapter metadata. Following are the changes required:-

i) Remove old Transport Protocol and replace with new Transport Protocol

ii) Remove old Message Protocol and replace with new Message Protocol

iii) Add new channel attribute and corresponding details

First of all, remove the section for the previous File Transport Protocol in the Outbound section of the file. Replace it with the following:-

  • Transport Protocol Name - NFS
  • Uses Message Protocol SyncGet (to be defined below)
  • Has only one channel attribute xpathToFile (to be defined below)

Next, remove the previous JCA10 Message protocol in the Outbound section of the file. Replace it with the following:-

  • Message Protocol name - SyncGet
  • Contains localejbs/ModuleProcessorExitBean in the module sequence with just one parameter JNDIName

Add details for channel attribute xpathToFile as shown below.

Update the adapter metadata in ESR by importing this modified SampleRA.xml file and activating the Adapter Metadata object.

Note: For the sake of simplicity, housekeeping is performed on the remaining content of the adapter metadata file even though there are a lot of attributes previously defined which are left unused/orphaned.

Source Code Changes

Next, we will update the source code of the adapter to modify its functionality. Unfortunately, certain parts of the sample adapter's source code is not written in a way that makes it easy to enhance or modify. Therefore, there will be numerous commenting and deletion of existing codes.

Additionally, we will be using the utility library used in my custom adapter modules in order to reuse some existing logic and simplify the development. So, head over to equalize-xpi-modules Latest Release and download the com.equalize.xpi.util.jar file. Then add it as an External JAR in the build path of the project as shown below.

i) SPIManagedConnection

First of all, we will comment out some of the private instance attributes that are used by the existing sample adapter logic.

Next, in the constructor of the class, comment out the trace statement. (Actually there is nothing really wrong with this statement, just that it incorrectly uses one of the commented out attributes above - optionally the statement can be modified accordingly instead of being commented out).

Still within the constructor, comment out the try-catch block (all the way until the end of the constructor) that accesses the old channel attributes (i.e. fileOutDir, fileOutPrefix, etc). This is replaced with a try-catch block that accesses the new channel attribute xpathToFile.

Delete the following methods (no screenshot shown):-

  • getOutFile()
  • getAsmaGet()
  • getAsmaError()

Create the following getter method getChannel() for private attribute channel.

In the destroy() method, comment out the statement as shown below.

In the cleanup() method, comment out the if-else block as shown below.

ii) XIConfiguration

Similar to above, comment out the logic that uses the old channel attributes. This part of the logic ensures that the adapter framework is able to read the channel attributes during initialization or when a channel is added. For simplicity, we will not change the name of the variables (dir & name) that store the retrieved values.

As shown below, comment out the old attributes in methods channelAdded() and init() and add logic using xpathToFile.

In method getChannelStatus(), comment out the section that uses the old attributes and add logic using xpathToFile.

iii) CCIInteraction

Delete the following methods (no screenshot shown):-

  • send()
  • call()

Comment out the existing section that executes the send() or call() method. This is where we will be introducing the core part of the new logic to fulfill the requirement above. Add a new statement that uses a new method retrieveFile() as shown below.

Subsequently, add logic for method retrieveFile() using the following code:-


    private Record retrieveFile (InteractionSpec ispec, Record input, SPIManagedConnection mc) throws ResourceException {
    Message msg = ((XIMessageRecord) input).getXIMessage();
    MessageKey amk = new MessageKey(msg.getMessageId(), MessageDirection.INBOUND);
        try {
        // Parse the XML input using DOM and evaluate the XPath expression
    ConversionDOMInput domIn = new ConversionDOMInput(msg.getDocument().getText());
    String xpathToFile = mc.getChannel().getValueAsString("xpathToFile");
    String inFile = domIn.evaluateXPathToString(xpathToFile);
    this.audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "XPath expression: " + xpathToFile);
    this.audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "XPath expression value: " + inFile);
    // Retrieve the file contents
    InputStream inpStr = new FileInputStream(new File(inFile));
    ByteArrayOutputStream baos = Converter.toBAOS(inpStr);
    // Create response XI message
    this.audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File retrieved, constructing response message");
    XIMessageRecordImpl output = new XIMessageRecordImpl(msg.getToParty(),msg.getFromParty(),
      msg.getToService(), msg.getFromService(),
      msg.getAction());
    Message response = output.getXIMessage();
    // Populate payload and attributes of response message
    XMLPayload payload = response.createXMLPayload();
    payload.setContent(baos.toByteArray());
    payload.setName("MainDocument");
    payload.setDescription("EQ Adapter Synchronous Response");
    payload.setContentType("application/xml");
    response.setDocument(payload);
    response.setRefToMessageId(msg.getMessageId());
    this.audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Response message construction completed");
    return (Record) output;
    } catch (Exception e) {
    this.audit.addAuditLogEntry(amk, AuditLogStatus.ERROR, e.getMessage());
    ResourceException re = new ResourceException(e.getMessage());
  TRACE.throwing("retrieveFile (InteractionSpec ispec, Record input, SPIManagedConnection mc)", re);
  throw re;
    }
    }






Ensure that any missing import statements are added accordingly.

In a nutshell, the above logic will be executed when the receiver channel processes a message. It determines the dynamic file that needs to be retrieved based on the evaluated value of Xpath expression in the input payload. It then retrieves the file content and constructs the response payload based on it.

Deployment Descriptor Changes

The following is an optional change to the ra.xml file. As described in previous part, this does not affect functionality.

Manifest File Changes

Prior to deployment, it is recommended to change the version number of the deployment in the SAP_MANIFEST.MF file. In the example below, it is changed to 1.0.0 to indicate the first major release of this adapter based on Semantic Versioning.

Note: If there is a need for multiple trial and error deployments prior to a proper release, we can supplement the versioning with an additional fourth digit(s) and increment it at each new deployment, i.e. 1.0.0.1, 1.0.0.2, 1.0.0.3.

Export and Deployment

Once this is all done, we are nearly ready for deployment. Before that, we need to ensure that the External JAR file for the utility library is also included in the RAR project. Copy and paste the file into the connectorModule folder of the RAR project as shown below.

Proceed to complete the steps required for deployment (refer to steps in Part 1)

  • Export JAR file of adapter project to connectorModule folder of RAR project
  • Export RAR file of RAR project
  • Undeploy previous version if already deployed so that there is no version clash during deployment
  • Deploy RAR file to PI server

Configuration and Testing

We are now ready to configure the adapter and test it out.

Configure a receiver channel using the custom adapter. The new transport protocol and message protocol will be reflected during selection of the adapter type.

Subsequently, the new channel attribute will be available for input. Enter the XPath expression as follows:-

After the channel has been activated, configure an integration scenario (classical, ICO or IFlow) that uses the receiver channel. This step will not be covered in this post.

For testing, I will try to retrieve a file from the home directory of the PI admin user. The screenshot below shows the CSV file that I intend to retrieve.

Using the built-in test functionality, a request message is triggered to the integration scenario. The message contains an XML payload with the full path to the CSV file.

After the message has been triggered and processed successfully, we can view the following log entries generated by the adapter logic in the message log.

Finally, we are able to view the content of the retrieved file within the response message's payload.

Source Code

Both Eclipse projects (adapter and RAR) are available in the following GitHub repository.

GitHub equalize-xpi-adapter-sample repository

Conclusion

Phew! Finally, after so many elaborate steps, we have managed to customise the adapter's functionality according to the requirement.

As demonstrated, although custom adapter development might seem overwhelmingly complex, once we dissect it into bite-size pieces, it is not impossible to gain an understanding of it and develop an adapter to meet a particular integration requirement.

It is important to note that this series is not meant to cover every aspect of custom adapter development, but to introduce the basic and key concepts in order to lower the entry barrier for such developments. As such, the source code modifications are done in a simple manner with the aim of introducing the concepts. Therefore, it is by no means the definitive way to develop a production-ready adapter. Once one is familiar with adapter development, it is recommended that the source code be enhanced via the usual techniques of modularisation, refactoring or usage of design patterns.

Next up in this series, we will be looking at changing the sender side functionality to an HTTP poller with OAuth 2.0 authentication.

Other Parts of this Series

Demystifying Custom Adapter Development: Part 1a - Cloning the Sample JCA Adapter

Demystifying Custom Adapter Development: Part 1b - Cloning the Sample JCA Adapter

Demystifying Custom Adapter Development: Part 2 - Examining the Adapter's Key Classes and Methods

Demystifying Custom Adapter Development: Part 3 - Examining the Deployment and Metadata Files

Demystifying Custom Adapter Development: Part 5 - Creating an HTTP Poller with OAuth 2.0 authenticat...

6 Comments
Labels in this area