Integration of SAP PI/PO with RabbitMQ AMQP Broker via JMS
Integration between SAP PI/PO and message oriented middleware / broker is one of commonly faced requirements – and this is where Java Message Service (JMS) is often used to fulfil this requirement. But JMS is a Java focused standard, so it is relatively complex to utilize JMS message broker in heterogeneous landscape of message producing and consuming systems and applications, which are running on various platforms and implemented using different programming languages. Even though some JMS brokers support variety of protocols which can be used by non-Java clients (a good example is support of Streaming Text Oriented Messaging Protocol (STOMP) for Ruby and Python applications and Microsoft Message Queuing Protocol (MSMQP) for .Net applications) and can be bridged to JMS, this brings complexity to configuration and maintenance of the JMS broker, increases technical debt, and in some cases is not technically feasible at all.
Currently SAP PI/PO doesn’t support AMQP out of the box – in contrast to JMS adapter, there is no SAP standard adapter that implements AMQP client functionality and can communicate with message broker using AMQP.
One of options that can be used to overcome this standard limitation, is installation and usage of 3rd party adapter – for example, Advantco AMQP Adapter (https://www.advantco.com/product/adapter/amqp). Usage of this adapter was described by Peter Ha in his blogs Advantco AMQP Adapter for SAP PI. and SAP PI – RabbitMQ AMQP 0-9-1 integration.
In this blog, I would like to describe another alternative which doesn’t require additional adapters and is based on usage of SAP PI/PO standard JMS adapter – to be more precise, usage of JMS based communication between SAP PI/PO and AMQP broker. In a demo, I use RabbitMQ AMQP broker – probably one of the most commonly used AMQP brokers at the moment. The idea behind this approach is to establish messaging interoperability between SAP PO and AMQP broker using JMS API which is well supported by JMS adapter of SAP PO.
RabbitMQ provides RabbitMQ JMS Connector which implements JMS 1.1 and enables JMS communication between JMS client (here, SAP PO) and RabbitMQ server. The connector consists of two parts:
- JMS client library – to be deployed and used by JMS client;
- JMS server plugin – to be installed on RabbitMQ server
Scope of the demo is to illustrate connectivity and interoperability of SAP PO system with RabbitMQ server where RabbitMQ is a receiver system. The same approach can be potentially used to configure scenarios where RabbitMQ is a sender system for SAP PO.
In RabbitMQ, following AMQP entities have been configured:
- Durable exchange topic test.po.topic – used as a destination for messages produced by SAP PO;
- Durable queue test.po.queue – used as a destination for arbitrary AMQP consumer.
For the exchange topic, binding to a queue has been created with routing key test_po.
The flow is depicted on the illustration below:
Configurations of exchange and queue in RabbitMQ are illustrated below:
(if necessary, you may find overview of main concepts and terms used in RabbitMQ and AMQP in general at RabbitMQ – AMQP 0-9-1 Model Explained).
In the demo, I use RabbitMQ server which was downloaded from https://www.rabbitmq.com/ (release: RabbitMQ 3.5.6). JMS connector for RabbitMQ was downloaded from http://pivotal.io/ (release: JMS Client 1.4.4).
Installation and configuration of JMS connector is described in details in documentation provided by vendor (for example in “Installing and Configuring JMS Client for Pivotal RabbitMQ” located at Pivotal RabbitMQ Documentation | Pivotal Docs).
The first step is to install JMS server plugin on RabbitMQ server using command rabbitmq-plugins.
The next step is to deploy JMS driver (which is contained in downloaded RabbitMQ JMS client library) to SAP PO system. This is done using the standard approach which is applicable for deployment of any other JMS driver – for detailed steps, refer to the SAP Note 1138877. I used SAP SDA Maker Tool to simplify the process of the required SDA file assembly – regarding SDA Maker Tool, refer to the SAP Note 1987079. When assembling the SDA file, please note that not only RabbitMQ JMS client library shall be included in the archive, but also its dependencies, which all can be found in distribution of JMS connector for RabbitMQ and are listed in the documentation referred above.
After JMS driver for RabbitMQ is deployed to SAP PO system, we are ready to configure the receiver communication channel. The configured JMS receiver communication channel shall be configured to use generic JMS broker access mode – which is, transport protocol shall be Access JMS Provider Generically. There are already a couple of useful blogs which describe how to use generic JMS broker access mode in JMS adapter (that time, when integrating SAP PI/PO with Apache ActiveMQ JMS broker), so it may make sense to look through them to get more diversified outlook at this functionality:
- PI/XI: ActiveMQ – free but yet powerful JMS provider written by Michal Krawczyk;
- How to Integrate Fuse MQ with SAP PI 7.4 using JMS written by Nitin Mehta.
Generally speaking, besides JMS common parameterization (tab “Parameters” > “Processing”), when configuring generic access to JMS broker, it is very important to provide advanced parameterization (tab “Parameters” > “Advanced”). Here we specify classes which are to be used by the communication channel when establishing connection to the broker (JMS connection factory implementing class) and to the destination registered on the broker (JMS destination implementing class), as well as arguments required to instantiate respective objects (connection and destination).
JMS connection factory implementing full class name is specified in parameter JMS.QueueConnectionFactoryImpl.classname, JMS destination implementing class – in parameter JMS.QueueImpl.classname. For each of specified classes, it is necessary to provide arguments which contain specification of connectivity details to the broker and destination details. There are two ways to achieve this:
- Providing parameters as arguments for a constructor method of the respective class. Following this approach, parameters JMS.QueueConnectionFactoryImpl.constructor and JMS.QueueImpl.constructor (one constructor entry for each of classes specified earlier) should be added in communication channel advanced configuration. Argument values for each constructor entry are provided comma-delimited and preceded with argument type specification;
- If the respective class has setter methods for effective parameters, they can be used instead of a constructor entry. Corresponding parameters in communication channel advanced configuration have follow naming convention JMS.QueueConnectionFactoryImpl.method.<method name> and JMS.QueueImpl.method.<method name>. Argument value for each setter method entry should also be preceded with argument type specification.
Please consult with documentation regarding connection factory and destination classes: not all classes may have setter methods, and it is critical to specify exactly same the amount of arguments of expected types as constructor method implementations expect (otherwise you will most likely observe NoSuchMethodException in SAP PO logs when this class constructor will be called by JMS adapter at runtime).
The complete list of parameters maintained in communication channel advanced configuration together with their values for this demo is as following:
If you prefer using arguments for a constructor method instead of setter methods, parameterization above can be re-written into following for JMS destination implementing class:
|JMS.QueueImpl.constructor||java.lang.String Test_RabbitMQ_Topic, java.lang.String test.po.topic, java.lang.String test_po, java.lang.String null|
If you would like to establish connection to a non-default RabbitMQ virtual host, please also ensure that proper virtual host is specified in parameterization for invoked connection factory – this can be done by adding extra parameter JMS.QueueConnectionFactoryImpl.method.setVirtualHost with a value java.lang.String <virtual host name>.
The communication channel has been started successfully and got connected to RabbitMQ server:
In sake of test, I send several messages for the developed scenario – few SOAP messages like the one below:
These messages can be immediately observed in the queue at RabbitMQ (which means, messages have been sent out by SAP PO, delivered to the topic in RabbitMQ and forwarded to the queue, from where it can now be retrieved and processed by some AMQP consumer application):
As it can be seen, the nature of interoperability between SAP PO and RabbitMQ remains JMS based – even though message consumers are likely to be AMQP clients for RabbitMQ, message producer (SAP PO) is still a JMS client and doesn’t really utilize AMQP capabilities within this approach.
It should also be noted that the described implementation is vendor specific – in other words, the implementation and demo are based on functionality and libraries that are provided by RabbitMQ specifically for their AMQP broker. In case of using AMQP brokering application delivered by another vendor, the one should check documentation in order to verify if the used AMQP broker supports similar capabilities. Absence of generic solution and risk of it being inappropriate for some implementations of AMQP brokers is a major disadvantage of the described approach (in contrast to AMQP adapter which is designed to support literally any AMQP compatible broker) that should be taken into consideration when designing integration of SAP PO with the specific AMQP broker.