Skip to Content
Author's profile photo Vadim Klimov

Integration of SAP PI/PO with RabbitMQ AMQP Broker via JMS

Intro

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.

 

In heterogeneous landscape, an alternative to JMS broker and bridging to platform specific protocols is complete replacement of JMS broker with generic platform agnostic message broker – and this is where the one may benefit from using Advanced Message Queuing Protocol (AMQP). One of advantages of usage of AMQP in contrast to JMS, is that it is intended to unify message brokering across various platforms – in such a way that applications written in Java, PHP, JavaScript, Ruby, C#, Python and other languages can all communicate with a single message broker. It is important to have clear differentiation between JMS and AMQP: JMS, being a messaging standard, defines Java messaging API, whereas AMQP, being a messaging protocol, defines wire-level protocol and principles of message structure and transmission over the network, it doesn’t provide industry standard API.

 

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

Demo

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:

Flow.png

Configurations of exchange and queue in RabbitMQ are illustrated below:

RabbitMQ exchange.png

RabbitMQ queue.png

(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:

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 receiver channel configuration.png

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:

 

Parameter Value
JMS.QueueConnectionFactoryImpl.classname com.rabbitmq.jms.admin.RMQConnectionFactory
JMS.QueueConnectionFactoryImpl.method.setHost java.lang.String e107184
JMS.QueueConnectionFactoryImpl.method.setPort java.lang.Integer 5672
JMS.QueueConnectionFactoryImpl.method.setUsername java.lang.String middleware_user
JMS.QueueConnectionFactoryImpl.method.setPassword java.lang.String TestPassword_2015!
JMS.QueueImpl.classname com.rabbitmq.jms.admin.RMQDestination
JMS.QueueImpl.method.setDestinationName java.lang.String Test_RabbitMQ_Topic
JMS.QueueImpl.method.setAmqpExchangeName java.lang.String test.po.topic
JMS.QueueImpl.method.setAmqpRoutingKey java.lang.String test_po
JMS.QueueImpl.method.setAmqpQueueName java.lang.String null
JMS.QueueImpl.method.setAmqp java.lang.Boolean true


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:

 

Parameter Value
JMS.QueueConnectionFactoryImpl.classname com.rabbitmq.jms.admin.RMQConnectionFactory
JMS.QueueConnectionFactoryImpl.method.setHost java.lang.String e107184
JMS.QueueConnectionFactoryImpl.method.setPort java.lang.Integer 5672
JMS.QueueConnectionFactoryImpl.method.setUsername java.lang.String middleware_user
JMS.QueueConnectionFactoryImpl.method.setPassword java.lang.String TestPassword_2015!
JMS.QueueImpl.classname com.rabbitmq.jms.admin.RMQDestination
JMS.QueueImpl.constructor java.lang.String Test_RabbitMQ_Topic, java.lang.String test.po.topic, java.lang.String test_po, java.lang.String null
JMS.QueueImpl.method.setAmqp java.lang.Boolean true

 

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:

JMS channel - startup.png


In sake of test, I send several messages for the developed scenario – few SOAP messages like the one below:

Message 1.png

PO messages.png

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):

RabbitMQ - messages overview in topic.png

RabbitMQ - messages overview in queue.png

RabbitMQ - messages.png

Outro

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.

Assigned Tags

      74 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Nitin Mehta
      Nitin Mehta

      Hey Vadim,

      Great information.

      Thanks for sharing this !!

      Regards

      Nitin

      Author's profile photo Former Member
      Former Member

      Hi Vadim,

      I´m doing exactly the same, but i´m getting this error for class com.rabbitmq.jms.admin.RMQConnectionFactory:

      "A channel error occurred. Detailed error (if any): com.sap.aii.adapter.jms.api.connector.ConnectorException: Cannot construct connection factory using constructor: ConstructorInvocationException: Error executing constructor invocation: <br>{ConstructorInvocation<br>{className=com.rabbitmq.jms.admin.RMQConnectionFactory,<br>invokeParams=[]<br>}; java.lang.reflect.InvocationTargetException"

      Any suggestion???

      Warm regards

      Juan

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Juan,

      Can you please provide a list of parameters JMS.QueueConnectionFactoryImpl.* that you maintained in a communication channel, and their values (you may mask actual host/port/user/password, etc. - I'm interested in checking how the value is composed and which types are used)? You may also want to create a forum thread for this issue so that we don't overload blog comments with a specific problem discussion.

      Regards,

      Vadim

      Author's profile photo Piotr Radzki
      Piotr Radzki

      Hello Vladim,

      First of all - thanks for this blog!

      In my case parameters looks like that (I masked some of them) and I’m getting the following error.

      JMS.QueueConnectionFactoryImpl.classname com.rabbitmq.jms.admin.RMQConnectionFactory
      JMS.QueueConnectionFactoryImpl.method.setHost java.lang.String test.xxxx.xxx.xx
      JMS.QueueConnectionFactoryImpl.method.setPort java.lang.Integer xxxx
      JMS.QueueConnectionFactoryImpl.method.setUsername java.lang.String test
      JMS.QueueConnectionFactoryImpl.method.setPassword java.lang.String test
      JMS.QueueImpl.classname com.rabbitmq.jms.admin.RMQDestination
      JMS.QueueImpl.method.setDestinationName java.lang.String Test_RabbitMQ_Topic
      JMS.QueueImpl.method.setAmqpExchangeName java.lang.String e.test
      JMS.QueueImpl.method.setAmqpRoutingKey java.lang.String test
      JMS.QueueImpl.method.setAmqpQueueName java.lang.String q.test
      JMS.QueueImpl.method.setAmqp java.lang.Boolean true

      What about “Processing” tab of JMS receiver adapter, is there a need for any specific configuration or configuration using parameters is enough in “Advanced” tab ?

      On “Processing” tab of JMS receiver adapter I specified:

      Transactional JMS Session (Recommended) – is checked

      JMS ReplyTo Queue Name = RabbitMQReply

      JMS Queue/Topic User = test

      JMS Queue/Topic Password = test

       

      The rest I left as it was in default.

       

      Still getting this error:

      A channel error occurred. Detailed error (if any) : com.sap.aii.adapter.jms.api.connector.ConnectorException: Cannot construct connection factory using constructor: ConstructorInvocationException: Error executing constructor invocation:
      {ConstructorInvocation
      {className=com.rabbitmq.jms.admin.RMQConnectionFactory,
      invokeParams=[]
      }: java.lang.reflect.InvocationTargetException

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hello Piotr,

       

      Verbose trace of the failing communication channel at its startup shall provide mode details regarding what the issue is (InvocationTargetException is a higher level exception, which intention is to wrap the concrete nested exception thrown by an invoked method - here, constructor of the connection). If possible, it would be great to see XPI Inspector trace for this channel so that you can track all nested exceptions down to cause.

       

      Can you also give a try to setting:

      • Value of JMS.QueueImpl.method.setDestinationName same as value of JMS.QueueImpl.method.setAmqpExchangeName, which is an exchange name registered on RabbitMQ,
      • Value of JMS.QueueImpl.method.setAmqpQueueName equal to java.lang.String null.

      Together with this, please check if virtual hosts are used in RabbitMQ configuration - if so (and if not default virtual host is to be used), set additional parameter JMS.QueueConnectionFactoryImpl.method.setVirtualHost with a value java.lang.String <virtual host name>.

       

      I didn't have to customize processing parameterization (tab 'Processing') - in my case, I left parameters on that tab with their default values.

       

      Regards,

      Vadim

      Author's profile photo Piotr Radzki
      Piotr Radzki

      Hello Vadim,

      it was a while, in the meantime we found out that some of the libraries were missing in the initial deployment to SAP PO of RabbitMQ lib.

      After we deployed missing libraries and we started Communication Channel again we get “connection time out”. In general it was the issue related to Network setup and open connectivity between our SAP PO system and RabbitMQ system.

      After the connection is open now we are having the communication channel status as succesfully started and connected to destination.

      Unfortunatelly when we are testing and trying to send some dummy messages to RabbitMQ we are getting errors:

      reply-code=403, reply-text=ACCESS_REFUSED – access to exchange ‘jms.durable.topic’ in vhost ‘/’ refused for user ‘xxxxxx’, class-id=40, method-id=10

      instead of xxxx there is of course proper username.

      I think its related to the setup on RabbitMQ side and its addressed to my colelagues responsible for MQ. Looking forward to solve it finaly ?

      BR,

      Piotr

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Piotr,

      You are absolutely right: the error ACCESS_REFUSED that you mentioned, is not related to PO side, but is caused by missing write permissions for the given user to the given exchange on RabbitMQ side. RabbitMQ has good documentation about how permissions are managed and configured there: https://www.rabbitmq.com/access-control.html .

      Regards,

      Vadim

      Author's profile photo Piotr Radzki
      Piotr Radzki

      RabbitMQ side was adjusted and I also removed one not necessary parameter from communication channel that I've set inititaly: JMS ReplyTo Queue Name.

      We have tested it and are able to send messages from SAP PO to RabbitMQ succesfully!

      Thanks for your blog it help a lot!

      Now I will setup scenario with Sender JMS adapter to allows RabbitMQ send messages to SAP PO. But I feel it will be much easier now.

      All the best for you Vadim!

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Glad to hear it finally worked well for you, Piotr. And good luck with RabbitMQ sender flow configuration!

      Author's profile photo Andrej Dukovski
      Andrej Dukovski

      Hi Piotr, hi everybody.

      Ij

      I have already successfully configured the receiver channel, thanks to Vadim.

      But I have no luck with the sender channel.

      Have you managed to successfully configure RabbitMQ sender?

       

      My ‘non-working’ configuration is as follows:

       

      JMS.QueueConnectionFactoryImpl.classname com.rabbitmq.jms.admin.RMQConnectionFactory
      JMS.QueueConnectionFactoryImpl.method.setHost java.lang.String x.x.x.x
      JMS.QueueConnectionFactoryImpl.method.setPort java.lang.Integer 5672
      JMS.QueueConnectionFactoryImpl.method.setVirtualHost java.lang.String xxxxxxx
      JMS.QueueConnectionFactoryImpl.method.setUsername java.lang.String middleware_user
      JMS.QueueConnectionFactoryImpl.method.setPassword java.lang.String TestPassword
      JMS.QueueImpl.classname com.rabbitmq.jms.admin.RMQDestination
      JMS.QueueImpl.method.setDestinationName java.lang.String Test_RabbitMQ_Topic
      JMS.QueueImpl.method.setAmqpExchangeName java.lang.String null
      JMS.QueueImpl.method.setAmqpRoutingKey java.lang.String null
      JMS.QueueImpl.method.setAmqpQueueName java.lang.String xxx.test.queue
      JMS.QueueImpl.method.setAmqp java.lang.Boolean true

       

       

      The channel is running (green) showing:

       

      connected to destination: RMQDestination{destinationName='Test_RabbitMQ_Topic', queue(permanent, amqp)', amqpExchangeName='null', amqpRoutingKey='null', amqpQueueName='xxx.test.queue'}

       

      but nothing is happening and no messages are pulled from the queue.

      If I uncheck the “Use Message Listener Based Connector”, I get the following error:

      Error receiving JMS message : while trying to invoke the method java.lang.Object.toString() of a null object returned from java.util.Map.get(java.lang.Object)

       

      I also wonder where to define the pooling interval (in processing tab or as an additional parameter)? Is the processing tab relevant at all? If so, should the listener based connector be checked or unchecked?

       

      Best regards,

      Andrej

       

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Andrej,

      I recall we had the discussion on configuration of JMS adapter for polling messages from RabbitMQ with Sandra some time ago, where there were issues with particular parameterization required in JMS sender channel - hence, please have a look in a forum thread PI Sender JMS RabbitMQ Integration, it might be helpful in your case, too. Few points to pay attention to: a) in polling scenarios, JMS adapter shall poll from RabbitMQ's queue (hence, topic specification in channel configuration is redundant), b) there are few JMS specific message properties that are advisable to be set in the message to make it successfully polled by JMS adapter (this originates from JMS specification).

      As for polling interval, please use configuration parameters provided on the tab 'Parameters' > 'Processing'.

      Regards,

      Vadim

      Author's profile photo Andrej Dukovski
      Andrej Dukovski

      Dear Vadim,

      Thank you very much for your quick reply. I solved the issue by following the thread you suggested.
      Indeed, there was a problem with message properties.

      Kind regards, Andrej

      Author's profile photo Piotr Radzki
      Piotr Radzki

      Hello Vadim,

      I received requirement from my RabbitMQ colleague to provide 2 additional parameters ,they look like message header parameters but non JMS related:

      type = 'new'

      content_type = '<object_name>'

      Did you faced simillar requirement? As far as I can see its hard to push such parameters.

      Do you know if its feasible using described here approach with JMS adapter and AMQP modules for Receiver adapter ?

      BR,

      Piotr

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Piotr,

      I'm not sure this kind of requirements can be fulfilled with the approached described here. Reason for this is, when we make use of RabbitMQ's JMS client library, PI/PO system interacts with the message in the way as if it would be a generic JMS message (and has access to message's JMS properties), but it will not have awareness of any additional properties that are not a part of JMS specification. Moreover, some properties are defaulted by RabbitMQ's JMS client library - 'content_type' being one of them. It might be worth checking discussion we had in regards to a similar requirement - https://archive.sap.com/discussions/thread/3909380. Although it is now possible to set content type using native AMQP library of RabbitMQ, as to my knowledge and outlook into implementation of JMS library for RabbitMQ, this is not something that has been exposed within the JMS library.

      Regards,

      Vadim

      Author's profile photo Piotr Radzki
      Piotr Radzki

      Thanks Vadim, I have same understanding of the topic. Nevertheless thanks for looking back into this.

      RabbitMQ colleagues made a workaround using RoutingKey and route the message properly based on that.

       

      BR,

      Piotr

      Author's profile photo Piotr Radzki
      Piotr Radzki

      To elaborate more on the topic, what I was able to do so far is to influence message header parameters but not message properties:

      I used described already appraoch specifying Additional JMS Message Properties:

      I used adapter modules to populate value for these parameters:

      It resulted with below messsage on RabbitMQ side, we have populated header parameters.

      But actual requirement is to populate message properties as below:

      Is it possible?

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Not something I would be aware of. When we discussed possibility of manipulating header values for constructed messages earlier, this ended up with the similar approach you used - handling JMS headers of the message, not headers of the AMQP message.

      Author's profile photo Piotr Radzki
      Piotr Radzki

      Hi Vadim Klimov

      we just successfully went live with Sender JMS adapter for RabbitMQ as well.

      And your tips about JMS header parameters helped a lot (from here)

      Thanks!

      BR,

      Piotr

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Really great news, Piotr, happy for you and the project team - please accept my congratulations!

      Author's profile photo Piotr Radzki
      Piotr Radzki

      Hello Juan,

       

      Did you solved this issue? Or maybe did you started a discussion in SCN?

      I’m facing exactly same error and looking actively for solution.

       

      Best Regards,

      Piotr

      Author's profile photo Former Member
      Former Member

      Hi Vadim,

      We have tried SAP PI/PO with RabbitMQ AMQP Broker via JMS adapter as per your documentation and able to connect the server and publish the message from SAP PO JMS to RabbitMQ queue. However the message format is not readable i.e we tried to publish the soap message but the message contains the entire XML instead of actual message.Please find attached image for the sample message format in RabbitMQ queue.

      XML Message which we sent from SAP PO to RabbitMQ JMS Queue:

      <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn::XXXXXXXXX:JMSPOC">
      <soapenv:Header/>
      <soapenv:Body>
      <urn:MT_SOAP_Sen>
      <!--Zero or more repetitions:-->
      <Header>
      <ID>100</ID>
      <Text>Testing JMS</Text>
      </Header>
      </urn:MT_SOAP_Sen>
      </soapenv:Body>
      </soapenv:Envelope>

      Can you help us to resolve the issue.

      Regards,

      Ravi

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hello Ravi,

      It is likely to be related not to specifics of communication with RabbitMQ, but configuration of the used receiver communication channel in part of which sections of the message are passed to the JMS provider and how they are converted before the message is published to the JMS topic. Hence, in the JMS receiver communication channel, please check:

      • Tab 'Parameters' > 'Processing', configuration for 'Mapping of message'. Here you can configure which part of the processed message will be dispatched to the JMS adapter;
      • Tab 'Module', which modules and with which configuration for them are configured before the module 'SendBinarytoXIJMSService' (the last in the sequence) is invoked. Here you can specify conversion logic for the processed message before it reaches the JMS adapter and gets published to the topic.

      Regards,

      Vadim

      Author's profile photo Former Member
      Former Member

      Hi Vadim,

      Thanks for the reply.We have not used any conversion module,still we are facing same issue.I am attaching JMS adapter configuration screens. Please help me if anything is missed from my end.

       

      Thanks

      Ravi

      Author's profile photo Former Member
      Former Member

      Maybe ActiveMq is more suited for this task

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Flor,

      Thank you, this is a valid point in certain circumstances - originally in Java centric environments, ActiveMQ fits very nicely as a JMS message broker, and together with AMQP (and some other alternative protocols) support that was introduced in it in later releases (AMQP support was introduced in release 5.8), its usage can be extended to other types of clients. I shall note, choice of the particular message broker commonly depends on already existing infrastructure - for example, a case that further led me to writing this blog, was based on the infrastructure where RabbitMQ cluster had already been setup and used productively in the company, and when we designed decoupled interfaces and looked into required dependencies / options for re-use of existing components (precisely, message brokers), already running highly available and robust RabbitMQ cluster was our preferred choice. In an organization that doesn't have any message broker in place, as you fairly pointed out, there are other alternatives and options to choose from.

      Regards,

      Vadim

      Author's profile photo Ramesh Mindaguditi
      Ramesh Mindaguditi

      Hi Vadim,

       

      We have tried SAP PI/PO integration with RabbitMQ AMQP Broker via JMS adapter as SAP PO as Consumer(Sender JMS Channel)

      1) If we set up all parameters suggested by you while publishing  message to RMQ our sender JMS channel is working fine but if few parameters missing our channel went to error (no message id generated as it's unable to pull the message) logs

      Error occurred while processing message: null. The detailed error (if any) is :  java.lang.IllegalArgumentException: The JMS message ID cannot be set as null.
      at com.sap.aii.adapter.jms.core.connector.JmsHeadersProfileImpl.setJMSMessageID(JmsHeadersProfileImpl.java:80)
      ....

      In RMQ We can see Unacked count 1 as this message not reached to SAP PI(or not acknowledged by SAP PI)

       

      After Restarting JMS sender Communication channel the un acked count  becomes 0 and PI didn't get any message and channel started polling freshly(Here we lost the message with improper headers) Even if we publish new message with all header params  to RMQ after this invalid message with out restarting JMS channel then new message reaches to SAP PI and  unacked count becomes (again losing message)

       

      In both the cases  no message reached to  SAP PI(No message id generated except error log with illegal argument exception  ) for message with missing header param and  message is not available in RMQ.

      So here we lost one message.

      So how can we achieve integration with out message lost.

      I have read (RMQ docs)  generally  followed mechanism for publish consume model in RMQ

      1. Set explicit  acknowledgement  in Consumer side so RMQ will  keep the message until it gets acknowledgement by consumer as received.
      2. By any case message got error ed out in consumer we have to put it in Error_Queue of RMQ (need to configure this in Consumer)

       

      Can we achieve above two configurations in our JMS Sender channel(As it is the consumer in our scenario).

      I have gone through RMQ Client   libraries and found that explicit acknowledgement method in RMQMessageConsumer class

       

      void dealWithAcknowledgements(boolean ack, long dtag) {
      if (ack) {
      this.session.explicitAck(dtag);
      } else {
      this.session.unackedMessageReceived(dtag);
      }
      }

       

      Didn't get any method to set it true in QueueImpl class.

      Can we configure error_queue in our sender JMS Channel.

      Please let me know your views.

      Thanks

       

       

       

       

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Ramesh,

       

      Let's firstly figure what causes the observed an error. The error "The JMS message ID cannot be set as null" commonly indicates that the JMS message's header field 'JMSMessageID' is missing. One option to check this is to trace sender channel when it polls a message, and check if that header exists in the polled JMS message. It will also be helpful if you describe which configuration parameters you remove to cause failure.

       

      Regarding acknowledgement mode, this is something that would normally be set up on session level (in contrast to connection and destination that are configured in the channel when using generic JMS provider access), but I don't think we can easily manipulate session properties from generic JMS provider access configuration.

       

      Regards,

      Vadim

      Author's profile photo Ramesh Mindaguditi
      Ramesh Mindaguditi

      Thanks Vadim.

                   It will also be helpful if you describe which configuration parameters you remove to cause failure.

               I didn’t give message id while publishing the message to RMQ Queue(Manual) to analyses the error. I hope in real time  application wouldn’t  miss header parameters  only  for few messages while publishing to RMQ Excahgne.

      I didn’t see any other error as of now (just done POC) and just  want to ensure no message lost and to know whether is there any possibility for Explicit ack and error_queue mechanism.

      Regards,

      Ramesh M.

       

       

      Author's profile photo Jordi Sales
      Jordi Sales

      Hi Vadim,

      I'm new integrating SAP PI with RabbitMQ and I have a problem with JMS Sender.

      I've read Sandra's thread (https://archive.sap.com/discussions/thread/3920564) and you said that is necessary to inform expiration property in messages published on RabbitMQ side.

      Is there any way of consume messages from RabbitMQ queue without setting expiration property?

      Thanks.

      Regards,

      Jordi.

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Jordi,

      Not the way I would be aware of - if the message was placed without property 'expiration', then JMS adapter wasn't able to poll it.

      Regards,

      Vadim

      Author's profile photo Jordi Sales
      Jordi Sales

      Thanks Vadim for the information.

      This is a great post, It help me a lot. 🙂

       

      Best Regards,

      Jordi.

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      You are welcome, Jordi. Glad it was helpful to you.

      Author's profile photo Jordi Sales
      Jordi Sales

      Hi Vadim,

      Now we are trying to  create a JMS receiver, and everything seems OK, we send a message and the channel put it to delivered.
      In RabbitMQ appear an attempt to connect but the message is not published into the exchange (this exchange is a direct exchange).
      In PI there is no error, but we are not sure about the value informed in the parameter "setDestinationName", which value we should inform here?

       

      Thanks.

       

      Jordi.

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Jordi,

      From the graphic you provided, it looks like RabbitMQ received something, as there was a spike in exchange activity. Hence, can you please check in JMS receiver channel configuration, in its processing properties, if delivery mode is set to persist JMS messages (that is the default mode - so unless you changed it explicitly manually, it shall be set).

      Good test on RabbitMQ side can be as following: stop consumer that polls messages from the queue, for which there is routing / binding from the exchange that you use, and then send a new message from PO. If RabbitMQ received message and persisted it, you shall be able to see activity spike in the exchange to which PO published a message, and then observe the message in the queue to which RabbitMQ routed the message from the exchange.

      As for the destination name, this is an alias for the destination - you can use the name that would make sense to you, or alternatively just re-use the same value as you use for AMQP exchange name, as the destination in this sense is the exchange.

      Regards,

      Vadim

      Author's profile photo Jordi Sales
      Jordi Sales

      Hi Vadim,

      Yes, we have delivery mode is set to persist JMS messages.

      We have already done the test you described, but the result was the same. Is it possible that Expiration should be informed in this case too? How could we Inform Expiration in JMS Receiver adapter?

      Thanks.

      Jordi.

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Jordi,

      By default, JMS receiver adapter sets message expiry period to unlimited, so if you want to change this, it is possible (check JMS message expiry period property in channel configuration), but if you don't set it manually, the channel will work as it will implicitly set unlimited expiry period.

      Can you send test message to the exposed exchange from the other publisher and see if it works? And, can you also collect a trace of a receiver communication channel in PO - it shall provide evidences of message transmission and publication to an exchange (or, given it is reflected in JMS terms, topic).

      Regards,

      Vadim

      Author's profile photo Jordi Sales
      Jordi Sales

      Hi Vadim,

      We just have successful tests with JMS sender, the problem was the Routing Key in RabbitMQ, this property was informed with an empty string and it was not possible to put this value in JMS parameter, even informing 'null' didn't work. We had to inform a fix value in Rabbit, because if not, the adapter only tried to connect, not publishing any message.

      Now we have JMS Sender and Receiver working correctly, thanks so much for your help.

      Regards.

      Jordi.

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Jordi,

      Thank you for the update, nice to hear you fixed the issue.

      Although, your comment regarding routing key makes me concerned. Routing key needs to be specified in the receiver channel (for example, via parameter 'JMS.QueueImpl.method.setAmqpRoutingKey') for scenarios when RabbitMQ receives a message published to its exchange, and needs to identify binding that it shall use to route the message to a corresponding queue. In receiver channel, when this parameter was set, and its value was set to non-null String value containing the routing key (which was reflection of routing key configured in RabbitMQ for the corresponding binding in the exchange configuration), it worked well for me. What kind of fix did you need to apply on RabbitMQ side and did you evidence that JMS adapter couldn't send routing key for some reason?

      Regards,

      Vadim

      Author's profile photo Jordi Sales
      Jordi Sales

      Sorry Vadim,

      I was wrong, the problem was with Receiver JMS Adapter. We only had to set a value to Routing Key in RabbitMQ, previusly, that property was informed with a empty string  and JMS adapter was not able to use JMS.QueueImpl.method.setAmqpRoutingKey with a empty string as parameter.

      Thanks so much for the help.

      Regards,

      Jordi.

      Author's profile photo Christof Johner
      Christof Johner

      Hello Vadim

      First of all: thanks for the interesting and nicely written blog.
      We’ve tried to implement your demo scenario and went through all the configuration steps.

      We’ve deployed the JMS driver: we’ve included the following client libraries:

      As a matter of fact the java class laoder shows this libraries after deployment:

      We’re using the following connection parameters (XXXX=masked):

      Now the problem where we don’t see the reason why. The communication channel show the following:

      …..Com.sap.aii.adapter.jms.api.connector.ConnectorException: cannot construct connection factory using constructor: ConstructorInvocationException: error executing constructor invocation:…<br> ConstructorInvocation className=com.rabbitmq.jms.admin.RMQConnectionFactory … Java.lang.reflect.InvocationTargetException…..
      at com.sap.aii.adapter.jms.core.connector.DirectConnectorImpl.createConnectionFactory(DirectConnectorImpl.java:105) ……..

      Do you have a suggestion where to dig further in order to resolve this problem? We’ve checked different blogs but didn’t find similar errors.

      Thanks for your feedback.

      Kind regards
      Christof

      Author's profile photo Christof Johner
      Christof Johner

      PS: the corresponding error messages in the message protocol when trying to send a message look like this:

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      All values in parameters that correspond to connection factory and queue constructors' properties, shall be preceeded with their type reference. In configuration you provided, parameter 'JMS.QueueConnectionFactoryImpl.method.setVirtualHost' has value of the virtual host 'XXXX-test', but the complete parameter value in this case shall become 'java.lang.String XXXX-test'.

      After this is adjusted, give another try to establish connection by the channel to RabbitMQ, if it will not be successful, something else that might be worth testing:

      • JMS.QueueImpl.method.setDestinationName = JMS.QueueImpl.method.setAmqpExchangeName = 'java.lang.String XXXX.xproduct',
      • JMS.QueueImpl.method.setAmqpQueueName = 'java.lang.String null'

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

      Hello Vadim

      thanks for your reply and suggestions.
      We've followed your advices and tried first with the following parameters:

      Afterwards with the following:

      But still exactly the same error as above:
      …..Com.sap.aii.adapter.jms.api.connector.ConnectorException: cannot construct connection factory using constructor: ConstructorInvocationException: error executing constructor invocation:…<br> ConstructorInvocation className=com.rabbitmq.jms.admin.RMQConnectionFactory … Java.lang.reflect.InvocationTargetException…..
      at com.sap.aii.adapter.jms.core.connector.DirectConnectorImpl.createConnectionFactory(DirectConnectorImpl.java:105) ……..

      Even with other combinations always the same error.

      Is there another way to further tackle down the source of the problem?

      Kind regards
      Christof

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      Will it be possible for you to trace startup of the channel (stop the channel, enable trace - such as XPI Inspector trace for this channel, and then start channel while trace is running)? This is to get more details on the context of the exception. I've checked configuration that I used, and in part of parameters that were passed to the connection factory constructor, I used the same combinations as you - so it will be helpful to see what nested exception (and potentially additional information on it) connection factory invocation throws in your setup.

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

      Hello Vadim

      We’ve tried to get more details with the XPI inspector and also log entries, but the information gathered did not really help to find the source of the problem:

      EXCEPTION]

      com.sap.aii.adapter.jms.api.connector.ConnectorException: Cannot construct connection factory using constructor: ConstructorInvocationException: Error executing constructor invocation:

      {ConstructorInvocation

      {className=com.rabbitmq.jms.admin.RMQConnectionFactory,

      invokeParams=[]

      }: java.lang.reflect.InvocationTargetException

      at com.sap.aii.adapter.jms.core.connector.DirectConnectorImpl.createConnectionFactory(DirectConnectorImpl.java:105)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.doConnect(ConnectorImpl.java:414)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.connectIfDisconnected(ConnectorImpl.java:237)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.connect(ConnectorImpl.java:220)

      at com.sap.aii.adapter.jms.core.channel.ChannelImpl.doStart(ChannelImpl.java:422)

      at com.sap.aii.adapter.jms.core.channel.ChannelImpl.start(ChannelImpl.java:179)

      at com.sap.aii.adapter.jms.core.channel.AdapterImpl$1.run(AdapterImpl.java:857)

      at com.sap.engine.core.thread.impl3.ActionObject.run(ActionObject.java:37)

      at java.security.AccessController.doPrivileged(Native Method)

      at com.sap.engine.core.thread.impl3.SingleThread.execute(SingleThread.java:185)

      at com.sap.engine.core.thread.impl3.SingleThread.run(SingleThread.java:302)

      Caused by: com.sap.aii.adapter.jms.api.base.ConstructorInvocationException: Error executing constructor invocation:

      {ConstructorInvocation

      {className=com.rabbitmq.jms.admin.RMQConnectionFactory,

      invokeParams=[]

      }: java.lang.reflect.InvocationTargetException

      at com.sap.aii.adapter.jms.core.common.InvokeUtils.invoke(InvokeUtils.java:548)

      at com.sap.aii.adapter.jms.core.common.InvokeUtils.invoke(InvokeUtils.java:514)

      at com.sap.aii.adapter.jms.core.connector.DirectConnectorImpl.createConnectionFactory(DirectConnectorImpl.java:101)

      ... 10 more

      Caused by: java.lang.reflect.InvocationTargetException

      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)

      at java.lang.reflect.Constructor.newInstance(Constructor.java:513)

      at com.sap.aii.adapter.jms.core.common.InvokeUtils.invoke(InvokeUtils.java:543)

      ... 12 more

      Caused by: java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

      at com.rabbitmq.jms.admin.RMQConnectionFactory.<init>(RMQConnectionFactory.java:32)

      ... 17 more

      Caused by:

      com.sap.aii.adapter.jms.api.base.ConstructorInvocationException: Error executing constructor invocation:

      {ConstructorInvocation

      {className=com.rabbitmq.jms.admin.RMQConnectionFactory,

      invokeParams=[]

      }: java.lang.reflect.InvocationTargetException

      at com.sap.aii.adapter.jms.core.common.InvokeUtils.invoke(InvokeUtils.java:548)

      at com.sap.aii.adapter.jms.core.common.InvokeUtils.invoke(InvokeUtils.java:514)

      at com.sap.aii.adapter.jms.core.connector.DirectConnectorImpl.createConnectionFactory(DirectConnectorImpl.java:101)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.doConnect(ConnectorImpl.java:414)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.connectIfDisconnected(ConnectorImpl.java:237)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.connect(ConnectorImpl.java:220)

      at com.sap.aii.adapter.jms.core.channel.ChannelImpl.doStart(ChannelImpl.java:422)

      at com.sap.aii.adapter.jms.core.channel.ChannelImpl.start(ChannelImpl.java:179)

      at com.sap.aii.adapter.jms.core.channel.AdapterImpl$1.run(AdapterImpl.java:857)

      at com.sap.engine.core.thread.impl3.ActionObject.run(ActionObject.java:37)

      at java.security.AccessController.doPrivileged(Native Method)

      at com.sap.engine.core.thread.impl3.SingleThread.execute(SingleThread.java:185)

      at com.sap.engine.core.thread.impl3.SingleThread.run(SingleThread.java:302)

      Caused by: java.lang.reflect.InvocationTargetException

      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)

      at java.lang.reflect.Constructor.newInstance(Constructor.java:513)

      at com.sap.aii.adapter.jms.core.common.InvokeUtils.invoke(InvokeUtils.java:543)

      ... 12 more

      Caused by: java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

      at com.rabbitmq.jms.admin.RMQConnectionFactory.<init>(RMQConnectionFactory.java:32)

      ... 17 more

      Caused by:

      java.lang.reflect.InvocationTargetException

      at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

      at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

      at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)

      at java.lang.reflect.Constructor.newInstance(Constructor.java:513)

      at com.sap.aii.adapter.jms.core.common.InvokeUtils.invoke(InvokeUtils.java:543)

      at com.sap.aii.adapter.jms.core.common.InvokeUtils.invoke(InvokeUtils.java:514)

      at com.sap.aii.adapter.jms.core.connector.DirectConnectorImpl.createConnectionFactory(DirectConnectorImpl.java:101)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.doConnect(ConnectorImpl.java:414)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.connectIfDisconnected(ConnectorImpl.java:237)

      at com.sap.aii.adapter.jms.core.connector.ConnectorImpl.connect(ConnectorImpl.java:220)

      at com.sap.aii.adapter.jms.core.channel.ChannelImpl.doStart(ChannelImpl.java:422)

      at com.sap.aii.adapter.jms.core.channel.ChannelImpl.start(ChannelImpl.java:179)

      at com.sap.aii.adapter.jms.core.channel.AdapterImpl$1.run(AdapterImpl.java:857)

      at com.sap.engine.core.thread.impl3.ActionObject.run(ActionObject.java:37)

      at java.security.AccessController.doPrivileged(Native Method)

      at com.sap.engine.core.thread.impl3.SingleThread.execute(SingleThread.java:185)

      at com.sap.engine.core.thread.impl3.SingleThread.run(SingleThread.java:302)

      Caused by: java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory

      at com.rabbitmq.jms.admin.RMQConnectionFactory.<init>(RMQConnectionFactory.java:32)

      ... 17 more

      Error starting channel: com.sap.aii.af.service.cpa.impl.object.ChannelImpl@b8059564 with ID=7b4b0b1df4ad30d5ada9ea9de6f8cd56 due to com.sap.aii.adapter.jms.api.connector.ConnectorException: Cannot construct connection factory using constructor: ConstructorInvocationException: Error executing constructor invocation:

      {ConstructorInvocation

      {className=com.rabbitmq.jms.admin.RMQConnectionFactory,

      invokeParams=[]

      }: java.lang.reflect.InvocationTargetException

      Do you have yet another approach how we can make this Scenario working?

      Kind regards

      Christof

      PS: with Java Producer and consumer Programm it is possible to write to and read from the queue above.

       

      Author's profile photo Christof Johner
      Christof Johner

      PS2: the parameters used for the Java producer /consumer programm is as follows:

      If this 12 Parameters are used in the PI CC channel the same error like above occurs.

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      Actually, XPI Inspector trace you provided, contains valuable input - note nested exception saying "java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory". This one would appear, if not all dependencies required by RabbitMQ JMS client library were added to com.sap.aii.adapter.lib.sda - here in particular, slf4j library seems missing. Please check that following libraries are added to com.sap.aii.adapter.lib.sda:

      • rabbitmq-jms
      • amqp-client
      • geronimo-jms_1.1_spec
      • slf4j-api

      For example, for the latest RabbitMQ JMS client version that is available currently in public repository (version 1.9.0), they will be:

      • rabbitmq-jms-1.9.0.jar
      • amqp-client-4.6.0.jar
      • geronimo-jms_1.1_spec-1.1.1.jar
      • slf4j-api-1.7.25.jar

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

      Hello Vadim

      Thanks, you’re right, so xpi inspector provided the necessary input to get one step further: I’ve added this library slf4j-api:

      Now this new error “Catching java.lang.UnsupportedClassVersionError: com/rabbitmq/client/ConnectionFactory” appears:

      Could this be due to our java version in the PI:

      I didn’t find and prerequisites on the java version to be used. Or is this yet another problem?

      Kind regards
      Christof

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      Yes, you are right: exception UnsupportedClassVersionError is thrown if JVM's runtime version is not compatible with the version, for which corresponding library was compiled. Your system uses SAP JVM 1.6, so libraries shall be compliant to this version. Hence, you can give a try downgrading version of used libraries to the version that is relevant for Java 1.6. Here, it is also important to note that is sake of consistency, it will be worth re-downloading all dependencies for RabbitMQ JMS client so that their versions correspond to what RabbitMQ JMS client library expects.

      At a time of a blog writing, I configured this scenario on PO 7.4 system, which was also based on JVM 1.6. Following set of library versions worked well for me that time:

      • rabbitmq-jms-1.4.4.jar
      • amqp-client-3.5.4.jar
      • geronimo-jms_1.1_spec-1.1.1.jar
      • slf4j-api-1.7.5.jar

      You can check if there is a version newer than RabbitMQ JMS client version 1.4.4, which is still compliant to Java 1.6 - that shall still work.

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

      Hello Vadim

      Thanks for the confirmation. I’ve downgraded the versions as follows:

      • rabbitmq-jms-1.4.7.jar (rabbitmq-jms-1.4.4.jar was not available anymore)
      • amqp-client-3.5.4.jar
      • geronimo-jms_1.1_spec-1.1.1.jar
      • slf4j-api-1.7.5.jar

      As a matter of fact this time it went a bit further but still refusing the connection:

      com.sap.aii.adapter.jms.api.connector.ConnectionException: Error creating Connection from JMS Connection Factory.: com.rabbitmq.jms.util.RMQJMSException: RabbitMQ connection was refused. RabbitMQ broker may not be available.

      However the port 5672 is open of the host when I telnet it from the PI-Server.

      If I run the java test-programm the RabbitMQ broker is available.

      Could the problem be now that the client version is to low in order to successfully connect to the broker?

       

      Kind regards

      Christof

       

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      HI Christof,

      Although it is generally nice to have client and server side aligned in versions, it is not always possible - such as the case you faced with the JMS client. Versions should normally be backward compatible - from the personal experience, we didn't have issues so far with the client side (in PO), when the server side (RabbitMQ message broker) got updated. To ensure this, it might be helpful to get RabbitMQ logs and see if there is anything in there, but connection refused type of error would commonly originate from lower level, network. When looking into details of the exception, I see it says: "Connection refused: connect (local port 63487 to address 0.0.0.0, remote port 5672 to address 127.0.0.1 (localhost))". I'm a bit confused why the request was sent to the localhost (unless RabbitMQ server runs on the same host as PO application server - but even in that case, it would be worth double checking if local or network adapter interface will be used by PO). Can you please check with the network team how routing is done and what they see about traffic leaving PO application server's host when you perform telnet test to RabbitMQ server from the terminal, and when you attempt to start communication channel targeting that RabbitMQ server?

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

       

      Hello Vadim

      finally it's working although with one little restriction: only IP hostname works,
      hostname does not yet.

      Let me first explain the issues we had to get out of the way:
      although the port 5672 was reachable by the "telnet" command it still got blocked
      by a firewall rule which impeded the construction of the connection.
      The has now been remedied by our network team and the connection works.

      The only problem is that we have to use the IP adresse instead of the hostname. Because our
      hostname contains special character like "-".
      It seems that the special character "-" gets interpreted as "?" in the RabbitMQ classes:

      The definition looks like this:

      The same applies for the user name: we had to omit "-" in the user Name.

      Do you know of any restrictions on the usage of special  characters like "-" in the RabbitMQ context?

       

      Kind regards

      Christof

       

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      Good to know you progressed a lot with the issue!

      I'm not aware of restrictions for dash (hyphen) symbol usage in either host name, or user name in RabbitMQ.

      Moreover, in one of our non-production systems, RabbitMQ broker's name contains hyphen in the name of the server, and a communication channel establishes connection successfully. I traced that receiver channel, and opposite to the issue you got with replacement of hyphen with the question mark, in the trace I've collected, hyphen was recognized correctly. In the trace, before RabbitMQ connection factory is invoked, can you check if host name with hyphen symbol is recognized correctly? At the beginning of a channel trace, there shall be series of calls that read additional parameters and make use of them further - can you see if host name gets corrupted right from the beginning, or this happens on later stages, when the value is passed to RabbitMQ's connection factory?

      As for a user name, checking client library, I see that user name is handled as String, so also shall not bring any restrictions for hyphen usage.

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

       

      Hello Vadim

       

      we could finally also sort ou the last problem with the hyphen:

      The string was copy pasted from the mail given from the provider.

      For some reason the hyphen was "dirty", after entering it manually the problem disappeared.

      We'd like to thanks you for prompt and expert advice and wish you well.

       

      Kind regards

      Christof

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      I'm very glad to hear that you finally made it work, congratulations! Good it all got sorted finally.

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

      Hello Vadim

      We have detected a follow up problem with special characters like umlauts like e.g. “ü”.

      E.g the German word “Bürste” is converted to “B?rste” in the JMS-adapter.

      How does this happen?

      In our scenario (ICO with IDOC-sender adapter  and JMS-receiver adapter) which is described above we are actually converting the idoc-xml to json format in the JMS adapter by using the converterClass XML2JSONConverter:

      JMS-Adapter:

      The VO-version of the message is still correct (xml-fomat):

      However the payload of the Json message version shows not the correct umlaut, which is “?” instead of “ü”:

      As a matter of fact the payload is the same in the RabbitMQ-Queue:

      What have we done to narrow down the problem? Instead of a JMS-receiver adapter we’ve used a file receiver adapter.

      File-Adapter with file type set to binary:

      Also with Converter class:

      The payload of the json-version of the message shows again “?” instead of “ü”:

      Also the VO-version is correct:

      But the produced file shows the correct umlaut:

      When we use file type “text” in the file adapter the same output as with JMS is produced:

      This leads us to the following conclusion:

      File-receiver-adapter:

      Obviously the file adapter works only with file type = “binary” and not with “text” in our example.

      JMS receiver adapter:

      In the JMS adapter the class ConvertMessageToBinary is called which should also convert to binary. But then the umlauts are still not properly translated.

      Do you have an idea how we can solve our umlaut problem in the JMS receiver adapter?

      Thanks for your feedback and kind regards

      Christof

      Author's profile photo Christof Johner
      Christof Johner

      Hi Vadim

      I've managed in the mean time to solve the issue by defining
      the following parameters in the JMS receiver adapter:
      JMS.Message.type=Text
      JMS.TextMessage.charset=ISO-8859-1

      This settings helped to get rid of the umlaut problem while
      using the FormatConversionBean.

      Kind regards
      Christof

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      Thank you for this valuable update – I’m glad to hear you found a workaround to overcome the issue. I was in touch with Eng Swee and we discussed the issue you faced with encoding of umlaut symbols. It might take some more time to investigate it, as the issue does not appear when we make unit tests of the adapter module in isolated environment (for example, when the module is called from within NWDS as a part of unit tests package that Eng Swee prepared), but is only reproduced when the module is called in context of a communication channel in Adapter Engine. So far, we could debug the module at Adapter Engine's runtime and observe that conversion that is done by the module, is error free and String representation of converted payload containing umlaut characters, is still fine, but those symbols are corrupted at later steps, which results in symptoms you evidenced and shared.

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

      Hi Vadim

      thanks for your feedback on the FormatConversionBean issue.

      In the mean time we have a new requirements regarding security:
      Our MQRabbit-Server-provider would like to run SSL.
      Do you know of a setup where SAP PI JMS with RabbitMQ AMQP Broker has
      been successfully configured with SSL?
      I've just seen some links for ActiveMQ https://blogs.sap.com/2016/09/30/jms-adapter-activemq-amq-with-ssltls-on-pi-74/ and MQ Series but not
      for MQRabbit. Do you think there is a chance to use SSL with in
      connection with a RabbitMQ AMQP Broker scenario.

      Thanks for your feedback.

      Kind regards
      Christof

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      I haven't yet had a chance to set up usage of AMQP over SSL for RabbitMQ. Though, it is worth mentioning that I see RabbitMQ JMS client supports usage of TLS/SSL - in particular, it provides parameter 'ssl' that can be set with the value 'true' in connection factory (refer to RabbitMQ JMS Client documentation). I looked through documentation and implementation of RMQConnectionFactory (that is implementing class used by JMS client in the communication channel), and I could see indication of explicit specification of trust store location. Hence, if you have RabbitMQ infrastructure that is enabled for AMQP over SSL usage, can you start from enabling SSL as an extra parameter for connection factory, and try establish connection to RabbitMQ? If it fails, then can you please collect a trace of the receiver communication channel, and check if it will have any valuable information in regards to the say how SSL handshake procedure is executed?

      Regards,

      Vadim

      Author's profile photo Philip G.
      Philip G.

      Hi Vadim,

      First of all, thanks for sharing your knowledge.

      I am trying to integrate SAP PI 7.5 with RabbitMQ 3.7.7 unsuccessfully, it would be great whether you could support me

      JMS Driver has been deployed
      > rabbitmq-jms-1.9.0.jar
      > amqp-client-5.3.0.jar
      > geronimo-jms_1.1_spec-1.1.1.jar
      > slf4j-api-1.7.25.jar

      Parameters

      JMS.QueueConnectionFactoryImpl.classname com.rabbitmq.jms.admin.RMQConnectionFactory
      JMS.QueueConnectionFactoryImpl.method.setHost java.lang.String 10.XXX.XX.XX
      JMS.QueueConnectionFactoryImpl.method.setPort java.lang.Integer 5672
      JMS.QueueConnectionFactoryImpl.method.setUsername java.lang.String XXXXX
      JMS.QueueConnectionFactoryImpl.method.setPassword java.lang.String XXXXX
      JMS.QueueImpl.classname com.rabbitmq.jms.admin.RMQDestination
      JMS.QueueImpl.method.setDestinationName java.lang.String amq.direct
      JMS.QueueImpl.method.setAmqpExchangeName java.lang.String amq.direct
      JMS.QueueImpl.method.setAmqpRoutingKey java.lang.String ARAP.BRADY.SAP.INVOICE_ACKNACK
      JMS.QueueImpl.method.setAmqpQueueName java.lang.String null
      JMS.QueueImpl.method.setAmqp java.lang.Boolean true

       

      Errors from Log Viewer

      Location
      com.sap.aii.adapter.jms.core.channel.ChannelLifecycleCallbackImpl.channelRemoved(Channel channel)

      Message
      Unable to remove subscriptioin id. Manually remove the same from the provider.

      Location
      com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.buildInvocations()

      Message
      Process additional parameters failed:
      [EXCEPTION]
      java.lang.NullPointerException: while trying to invoke the method java.lang.String.trim() of a null object returned from com.sap.aii.adapter.jms.core.common.StringUtils.substringAfterLast(java.lang.String, java.lang.String)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.stripMethodName(GenericConnectionProfileBuilderImpl.java:458)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.parseMethodInvocation(GenericConnectionProfileBuilderImpl.java:681)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.processAdditionalParameter(GenericConnectionProfileBuilderImpl.java:546)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.buildInvocations(GenericConnectionProfileBuilderImpl.java:474)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.createConnectionProfile(GenericConnectionProfileBuilderImpl.java:233)
      at com.sap.aii.adapter.jms.core.channel.ChannelProfileBuilderImpl.buildConnectionProfile(ChannelProfileBuilderImpl.java:117)
      at com.sap.aii.adapter.jms.core.channel.ChannelProfileBuilderImpl.constructChannelProfile(ChannelProfileBuilderImpl.java:78)
      at com.sap.aii.adapter.jms.core.channel.AdapterImpl.addOrReplaceChannel(AdapterImpl.java:809)
      at com.sap.aii.adapter.jms.core.channel.ChannelLifecycleCallbackImpl.channelAdded(ChannelLifecycleCallbackImpl.java:53)
      at com.sap.aii.af.service.administration.impl.ChannelLifecycleCallbackProxy.channelAdded(ChannelLifecycleCallbackProxy.java:63)
      at com.sap.aii.af.service.cpa.impl.callback.CallbackManager.executeCallbackForAdapterKey(CallbackManager.java:229)
      at com.sap.aii.af.service.cpa.impl.callback.CallbackManager.performChannelCallback(CallbackManager.java:200)
      at com.sap.aii.af.service.cpa.impl.cache.directory.DirectoryDataSAXHandler.putParsedObjsIntoCacheAndBroadcast(DirectoryDataSAXHandler.java:3092)
      at com.sap.aii.af.service.cpa.impl.cache.directory.DirectoryDataParser.updateCentralCache(DirectoryDataParser.java:123)
      at com.sap.aii.af.service.cpa.impl.cache.CacheManager.updateCacheWithDirectoryData(CacheManager.java:421)
      at com.sap.aii.af.service.cpa.impl.cache.CacheManager.performCacheUpdate(CacheManager.java:528)
      at com.sap.aii.af.service.cpa.impl.cache.CacheManager$CacheUpdateRunnable.run(CacheManager.java:313)
      at com.sap.engine.core.thread.impl3.ActionObject.run(ActionObject.java:37)
      at java.security.AccessController.doPrivileged(Native Method)
      at com.sap.engine.core.thread.impl3.SingleThread.execute(SingleThread.java:185)
      at com.sap.engine.core.thread.impl3.SingleThread.run(SingleThread.java:302)

      Location
      com.sap.aii.adapter.jms.core.channel.AdapterImpl.addOrReplaceChannel(ChannelcpaChannel)

      Message
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] There was an error parsing/constructing channel configuration profile. com.sap.aii.adapter.jms.api.channel.ChannelProfileBuildException: Additional parameter: JMS.QueueImpl.method.setAmqpExchangeName is not valid.: NullPointerException: while trying to invoke the method java.lang.String.trim() of a null object returned from com.sap.aii.adapter.jms.core.common.StringUtils.substringAfterLast(java.lang.String, java.lang.String)

      Many thanks!

      Philip

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hello Philip,

      Can you please stop the channel, enable XPI Inspector trace for it, and start channel again - this shall help in collection of runtime trace of connection establishment from JMS adapter of PO to RabbitMQ, and it shall be seen in the trace, what parameters were effectively passed to connection and destination constructors. From the table of parameters that you provided, I couldn't find a reason why parameter value JMS.QueueImpl.method.setAmqpExchangeName got considered as null by runtime (which would normally be a case when the parameter is missing or when there was typo in its name), so runtime trace will be handy here.

      Regards,

      Vadim

      Author's profile photo Philip G.
      Philip G.

      Hello Vadim,

      Thank you for answering.

      From XPI Inspector (Probably not the best way to share it)

      ⇦ with (com.sap.aii.af.service.cpa.impl.object.ChannelImpl@7735ceca with ID=b3ceef97e06b3d3e80b62c1b610aee26)
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueConnectionFactoryImpl.classname], Additional Parameter Value:[com.rabbitmq.jms.admin.RMQConnectionFactory]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueConnectionFactoryImpl.method.setHost], Additional Parameter Value:[java.lang.String 10.220.11.10]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueConnectionFactoryImpl.method.setPort], Additional Parameter Value:[java.lang.Integer 5672]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueConnectionFactoryImpl.method.setUsername], Additional Parameter Value:[java.lang.String rabbituat]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueConnectionFactoryImpl.method.setPassword], Additional Parameter Value:[java.lang.String |Dc1XtP{Q3ZiE.?a]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueImpl.classname], Additional Parameter Value:[com.rabbitmq.jms.admin.RMQDestination]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueImpl.method.setDestinationName], Additional Parameter Value:[java.lang.String amq.direct]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueImpl.method.setAmqpExchangeName], Additional Parameter Value:[java.lang.String amq.direct]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueImpl.method.setAmqpRoutingKey], Additional Parameter Value:[java.lang.String ARAP.BRADY.SAP.INVOICE_ACKNACK]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueImpl.method.setAmqpQueueName], Additional Parameter Value:[java.lang.String null]
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Additional Parameter Name: [JMS.QueueImpl.method.setAmqp], Additional Parameter Value:[java.lang.Boolean true]
      Constructed additionalchannelparams properties: {JMS.QueueImpl.method.setAmqpExchangeName=java.lang.String amq.direct, JMS.QueueConnectionFactoryImpl.method.setPort=java.lang.Integer 5672, JMS.QueueConnectionFactoryImpl.classname=com.rabbitmq.jms.admin.RMQConnectionFactory, JMS.QueueImpl.method.setDestinationName=java.lang.String amq.direct, JMS.QueueConnectionFactoryImpl.method.setHost=java.lang.String 10.220.11.10, JMS.QueueImpl.method.setAmqp=java.lang.Boolean true, JMS.QueueConnectionFactoryImpl.method.setUsername=java.lang.String rabbituat, JMS.QueueImpl.method.setAmqpQueueName=java.lang.String null, JMS.QueueImpl.method.setAmqpRoutingKey=java.lang.String ARAP.BRADY.SAP.INVOICE_ACKNACK, JMS.QueueImpl.classname=com.rabbitmq.jms.admin.RMQDestination, JMS.QueueConnectionFactoryImpl.method.setPassword=java.lang.String |Dc1XtP{Q3ZiE.?a}
      Must build connectionprofilefor Generic
      ⇦ with (com.sap.aii.af.service.cpa.impl.object.ChannelImpl@7735ceca with ID=b3ceef97e06b3d3e80b62c1b610aee26, {JMS.QueueImpl.method.setAmqpExchangeName=java.lang.String amq.direct, JMS.QueueConnectionFactoryImpl.method.setPort=java.lang.Integer 5672, JMS.QueueConnectionFactoryImpl.classname=com.rabbitmq.jms.admin.RMQConnectionFactory, JMS.QueueImpl.method.setDestinationName=java.lang.String amq.direct, JMS.QueueConnectionFactoryImpl.method.setHost=java.lang.String 10.220.11.10, JMS.QueueImpl.method.setAmqp=java.lang.Boolean true, JMS.QueueConnectionFactoryImpl.method.setUsername=java.lang.String rabbituat, JMS.QueueImpl.method.setAmqpQueueName=java.lang.String null, JMS.QueueImpl.method.setAmqpRoutingKey=java.lang.String ARAP.BRADY.SAP.INVOICE_ACKNACK, JMS.QueueImpl.classname=com.rabbitmq.jms.admin.RMQDestination, JMS.QueueConnectionFactoryImpl.method.setPassword=java.lang.String |Dc1XtP{Q3ZiE.?a})
      Additionalparams:{JMS.QueueImpl.method.setAmqpExchangeName=java.lang.String amq.direct, JMS.QueueConnectionFactoryImpl.method.setPort=java.lang.Integer 5672, JMS.QueueConnectionFactoryImpl.classname=com.rabbitmq.jms.admin.RMQConnectionFactory, JMS.QueueImpl.method.setDestinationName=java.lang.String amq.direct, JMS.QueueConnectionFactoryImpl.method.setHost=java.lang.String 10.220.11.10, JMS.QueueImpl.method.setAmqp=java.lang.Boolean true, JMS.QueueConnectionFactoryImpl.method.setUsername=java.lang.String rabbituat, JMS.QueueImpl.method.setAmqpQueueName=java.lang.String null, JMS.QueueImpl.method.setAmqpRoutingKey=java.lang.String ARAP.BRADY.SAP.INVOICE_ACKNACK, JMS.QueueImpl.classname=com.rabbitmq.jms.admin.RMQDestination, JMS.QueueConnectionFactoryImpl.method.setPassword=java.lang.String |Dc1XtP{Q3ZiE.?a}
      paramName=’JMS.QueueImpl.method.setAmqpExchangeName’
      params.get(paramName)=java.lang.String amq.direct
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] Now processing, propName: JMS.QueueImpl.method.setAmqpExchangeName, propVal: java.lang.String amq.direct
      Parsing method invocation from additional parameter name: JMS.QueueImpl.method.setAmqpExchangeName, value: java.lang.String amq.direct
      Method name passed to this class: JMS.QueueImpl.method.setAmqpExchangeName
      Suffix String : setAmqpExchangeName
      Number Format Exception occurred in parsing method name null
      Throwing java.lang.NumberFormatException: For input string: “setAmqpExchangeName”
       
      [EXCEPTION]
      java.lang.NullPointerException: while trying to invoke the method java.lang.String.trim() of a null object returned from com.sap.aii.adapter.jms.core.common.StringUtils.substringAfterLast(java.lang.String, java.lang.String)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.stripMethodName(GenericConnectionProfileBuilderImpl.java:458)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.parseMethodInvocation(GenericConnectionProfileBuilderImpl.java:681)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.processAdditionalParameter(GenericConnectionProfileBuilderImpl.java:546)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.buildInvocations(GenericConnectionProfileBuilderImpl.java:474)
      at com.sap.aii.adapter.jms.core.channel.GenericConnectionProfileBuilderImpl.createConnectionProfile(GenericConnectionProfileBuilderImpl.java:233)
      at com.sap.aii.adapter.jms.core.channel.ChannelProfileBuilderImpl.buildConnectionProfile(ChannelProfileBuilderImpl.java:117)
      at com.sap.aii.adapter.jms.core.channel.ChannelProfileBuilderImpl.constructChannelProfile(ChannelProfileBuilderImpl.java:78)
      at com.sap.aii.adapter.jms.core.channel.AdapterImpl.addOrReplaceChannel(AdapterImpl.java:809)
      at com.sap.aii.adapter.jms.core.channel.ChannelLifecycleCallbackImpl.channelAdded(ChannelLifecycleCallbackImpl.java:53)
      at com.sap.aii.af.service.administration.impl.AdminManagerImpl.notifyChannelActivationStateChanged(AdminManagerImpl.java:1140)
      at com.sap.aii.af.service.administration.impl.cluster.ClusterManager.eventReceivedSync(ClusterManager.java:924)
      at com.sap.aii.af.service.event.impl.worker.sync.SyncLocalWorker.work(SyncLocalWorker.java:71)
      at com.sap.aii.af.service.event.impl.worker.sync.AbstractSyncWorker.startWork(AbstractSyncWorker.java:40)
      at com.sap.aii.af.service.event.impl.EventManagerImpl.sendEventAndWaitForAnswer(EventManagerImpl.java:489)
      at com.sap.aii.af.service.event.impl.EventManagerImpl.sendEventAndWaitForAnswer(EventManagerImpl.java:358)
      at com.sap.aii.af.service.administration.impl.cluster.ClusterManager.notifyChannelActivationStateChanged(ClusterManager.java:600)
      at com.sap.aii.af.service.administration.impl.AdminManagerImpl.setChannelActivationState(AdminManagerImpl.java:942)
      at com.sap.aii.af.service.administration.impl.AdminManagerImpl.setChannelActivationState(AdminManagerImpl.java:837)
      at com.sap.aii.af.service.administration.impl.AdminManagerImpl.setChannelActivationState(AdminManagerImpl.java:826)
      at com.sap.aii.mdt.itsam.mbeans.utils.XIAdapterChannelStartStopUtil.setChannelsActivationState(XIAdapterChannelStartStopUtil.java:57)
      at com.sap.aii.mdt.itsam.mbeans.utils.XIAdapterChannelUtil.StartChannels(XIAdapterChannelUtil.java:472)
      at com.sap.aii.mdt.itsam.mbeans.channelmonitor.SAP_ITSAMXIAdapterChannelService_DevImpl.StartChannels(SAP_ITSAMXIAdapterChannelService_DevImpl.java:40)
      at com.sap.aii.mdt.itsam.mbeans.channelmonitor.SAP_ITSAMXIAdapterChannelService_Impl.StartChannels(SAP_ITSAMXIAdapterChannelService_Impl.java:328)
      at com.sap.aii.mdt.itsam.mbeans.channelmonitor.SAP_ITSAMXIAdapterChannelServiceWrapper.invoke(SAP_ITSAMXIAdapterChannelServiceWrapper.java:496)
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
      at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
      at com.sap.pj.jmx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:468)
      at com.sap.pj.jmx.server.interceptor.MBeanServerWrapperInterceptor.invoke(MBeanServerWrapperInterceptor.java:288)
      at com.sap.engine.services.jmx.CompletionInterceptor.invoke(CompletionInterceptor.java:612)
      at com.sap.pj.jmx.server.interceptor.BasicMBeanServerInterceptor.invoke(BasicMBeanServerInterceptor.java:277)
      at com.sap.jmx.provider.ProviderInterceptor.invoke(ProviderInterceptor.java:365)
      at com.sap.engine.services.jmx.RedirectInterceptor.invoke(RedirectInterceptor.java:340)
      at com.sap.pj.jmx.server.interceptor.MBeanServerInterceptorChain.invoke(MBeanServerInterceptorChain.java:367)
      at com.sap.engine.services.jmx.MBeanServerSecurityWrapper.invoke(MBeanServerSecurityWrapper.java:289)
      at com.sap.engine.services.jmx.ClusterInterceptor.invoke(ClusterInterceptor.java:813)
      at com.sap.pj.jmx.server.interceptor.MBeanServerInterceptorChain.invoke(MBeanServerInterceptorChain.java:367)
      at com.sap.lm.itsam.ui.connection.impl.ITSAMUIMBeanServerConnectionWrapper.invoke(ITSAMUIMBeanServerConnectionWrapper.java:379)
      at com.sap.tc.lm.itsam.ui.proxy.JMXGenericModelClassMBean.invokeOperation(JMXGenericModelClassMBean.java:610)
      at com.sap.tc.lm.itsam.ui.proxy.JMXAbstractModelClass.invokeOperation(JMXAbstractModelClass.java:159)
      at com.sap.tc.lm.itsam.co.ui.xi.channel.wd.model.SAP_ITSAMXIAdapterChannelService.StartChannels(SAP_ITSAMXIAdapterChannelService.java:226)
      at com.sap.tc.lm.itsam.co.ui.xi.channel.wd.pichanneldetailed.pichannelmoni.pichannelmonidetailed.PIChannelMoniDetailed.startorstopchannels(PIChannelMoniDetailed.java:778)
      at com.sap.tc.lm.itsam.co.ui.xi.channel.wd.pichanneldetailed.pichannelmoni.pichannelmonidetailed.wdp.InternalPIChannelMoniDetailed.startorstopchannels(InternalPIChannelMoniDetailed.java:677)
      at com.sap.tc.lm.itsam.co.ui.xi.channel.wd.pichanneldetailed.pichannelmoni.pichannelmonidetailed.SearchView.onActionStartChannel(SearchView.java:328)
      at com.sap.tc.lm.itsam.co.ui.xi.channel.wd.pichanneldetailed.pichannelmoni.pichannelmonidetailed.wdp.InternalSearchView.wdInvokeEventHandler(InternalSearchView.java:440)
      at com.sap.tc.webdynpro.progmodel.generation.DelegatingView.invokeEventHandler(DelegatingView.java:142)
      at com.sap.tc.webdynpro.progmodel.controller.Action.fire(Action.java:75)
      at com.sap.tc.webdynpro.clientserver.phases.ProcessingEventPhase.doHandleActionEvent(ProcessingEventPhase.java:159)
      at com.sap.tc.webdynpro.clientserver.phases.ProcessingEventPhase.execute(ProcessingEventPhase.java:94)
      at com.sap.tc.webdynpro.clientserver.window.WindowPhaseModel.processRequestPartly(WindowPhaseModel.java:162)
      at com.sap.tc.webdynpro.clientserver.window.WindowPhaseModel.doProcessRequest(WindowPhaseModel.java:110)
      at com.sap.tc.webdynpro.clientserver.window.WindowPhaseModel.processRequest(WindowPhaseModel.java:97)
      at com.sap.tc.webdynpro.clientserver.window.WebDynproWindow.processRequest(WebDynproWindow.java:515)
      at com.sap.tc.webdynpro.clientserver.cal.AbstractClient.executeTasks(AbstractClient.java:58)
      at com.sap.tc.webdynpro.clientserver.cal.ClientApplication.doExecute(ClientApplication.java:1671)
      at com.sap.tc.webdynpro.clientserver.cal.ClientApplication.doProcessing(ClientApplication.java:1485)
      at com.sap.tc.webdynpro.clientserver.session.ApplicationSession.doApplicationProcessingStandalone(ApplicationSession.java:908)
      at com.sap.tc.webdynpro.clientserver.session.ApplicationSession.doApplicationProcessing(ApplicationSession.java:880)
      at com.sap.tc.webdynpro.clientserver.session.ApplicationSession.doProcessing(ApplicationSession.java:357)
      at com.sap.tc.webdynpro.clientserver.session.RequestManager.doProcessing(RequestManager.java:326)
      at com.sap.tc.webdynpro.serverimpl.core.AbstractDispatcherServlet.doContent(AbstractDispatcherServlet.java:87)
      at com.sap.tc.webdynpro.serverimpl.wdc.DispatcherServlet.doContent(DispatcherServlet.java:101)
      at com.sap.tc.webdynpro.serverimpl.core.AbstractDispatcherServlet.doPost(AbstractDispatcherServlet.java:62)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
      at com.sap.engine.services.servlets_jsp.server.Invokable.invoke(Invokable.java:152)
      at com.sap.engine.services.servlets_jsp.server.runtime.RequestDispatcherImpl.doWork(RequestDispatcherImpl.java:373)
      at com.sap.engine.services.servlets_jsp.server.runtime.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:499)
      at com.sap.tc.webdynpro.serverimpl.wdc.ForwardServlet.doPost(ForwardServlet.java:77)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
      at com.sap.engine.services.servlets_jsp.server.Invokable.invoke(Invokable.java:152)
      at com.sap.engine.services.servlets_jsp.server.Invokable.invoke(Invokable.java:38)
      at com.sap.engine.services.servlets_jsp.server.HttpHandlerImpl.runServlet(HttpHandlerImpl.java:466)
      at com.sap.engine.services.servlets_jsp.server.HttpHandlerImpl.handleRequest(HttpHandlerImpl.java:210)
      at com.sap.engine.services.httpserver.server.RequestAnalizer.startServlet(RequestAnalizer.java:441)
      at com.sap.engine.services.httpserver.server.RequestAnalizer.startServlet(RequestAnalizer.java:430)
      at com.sap.engine.services.servlets_jsp.filters.DSRWebContainerFilter.process(DSRWebContainerFilter.java:38)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.servlets_jsp.filters.ServletSelector.process(ServletSelector.java:81)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.servlets_jsp.filters.ApplicationSelector.process(ApplicationSelector.java:278)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.httpserver.filters.WebContainerInvoker.process(WebContainerInvoker.java:81)
      at com.sap.engine.services.httpserver.chain.HostFilter.process(HostFilter.java:9)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.httpserver.filters.ResponseLogWriter.process(ResponseLogWriter.java:60)
      at com.sap.engine.services.httpserver.chain.HostFilter.process(HostFilter.java:9)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.httpserver.filters.DefineHostFilter.process(DefineHostFilter.java:27)
      at com.sap.engine.services.httpserver.chain.ServerFilter.process(ServerFilter.java:12)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.httpserver.filters.MonitoringFilter.process(MonitoringFilter.java:29)
      at com.sap.engine.services.httpserver.chain.ServerFilter.process(ServerFilter.java:12)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.httpserver.filters.SessionSizeFilter.process(SessionSizeFilter.java:26)
      at com.sap.engine.services.httpserver.chain.ServerFilter.process(ServerFilter.java:12)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.httpserver.filters.MemoryStatisticFilter.process(MemoryStatisticFilter.java:57)
      at com.sap.engine.services.httpserver.chain.ServerFilter.process(ServerFilter.java:12)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.httpserver.filters.DSRHttpFilter.process(DSRHttpFilter.java:43)
      at com.sap.engine.services.httpserver.chain.ServerFilter.process(ServerFilter.java:12)
      at com.sap.engine.services.httpserver.chain.AbstractChain.process(AbstractChain.java:78)
      at com.sap.engine.services.httpserver.server.Processor.chainedRequest(Processor.java:475)
      at com.sap.engine.services.httpserver.server.Processor$FCAProcessorThread.process(Processor.java:269)
      at com.sap.engine.services.httpserver.server.rcm.RequestProcessorThread.run(RequestProcessorThread.java:56)
      at com.sap.engine.core.thread.execution.Executable.run(Executable.java:122)
      at com.sap.engine.core.thread.execution.Executable.run(Executable.java:101)
      at com.sap.engine.core.thread.execution.CentralExecutor$SingleThread.run(CentralExecutor.java:328)
       
      [[ChannelName:CC_R_BRADY_RMQ_N,ChannelId: b3ceef97e06b3d3e80b62c1b610aee26]] There was an error parsing/constructing channel configuration profile. com.sap.aii.adapter.jms.api.channel.ChannelProfileBuildException: Additional parameter: JMS.QueueImpl.method.setAmqpExchangeName is not valid.: NullPointerException: while trying to invoke the method java.lang.String.trim() of a null object returned from com.sap.aii.adapter.jms.core.common.StringUtils.substringAfterLast(java.lang.String, java.lang.String)

       

      Many thanks!

      Philip

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hello Philip,

      Thank you for the trace. From it, I can see that additional parameters and their values were correctly recognized and an array of them was constructed (Additionalparams). It shall be noted that JMS.QueueImpl.method.setAmqpExchangeName comes first in that list. Later on, it can be seen that JMS adapter terminated with NumberFormatException right at the beginning of additional parameters' parsing process, so parameter JMS.QueueImpl.method.setAmqpExchangeName caused failure not because of the issue with this particular parameter, but just because it was first in the list.

      Similar symptom in JMS adapter behavior (failure to parse additional parameters resulting in NumberFormatException with similar call stack) is described in SAP Note 2290137 (JMS Adapter - Number Format Exception occurs when invoking method from additional parameters). Can you please check it and see if program correction / fix from that Note is applied in your system?

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

      Hello Vadim

      thanks for your feedback on my question (from the 17th September 2018)
      regarding the SSL configuration.
      I will get back on this ssl configuration issue and share my
      findings as soon as we start with it (in couple days).

      Before however we have to solve another configuration issue
      with the AmqpRoutingKey parameter. Maybe
      you could assist here with your expertise.
      Following situation: We want do send messages from SAP PI
      to another MQRabbit Server infrastructure (not the same from above).
      After sorting out the intial problems we have now a connection
      which is working, but only when we define a AmqpRoutingKey which
      is not a empty string (e.g. sap.customer), then we successfully
      send a message to the corresponding queue (so in this case on
      the MQrabbit server the routing key is defined as sap.customer).
      Now the point is that the application (spryker ehop) which runs
      against the MQrabbit server to consume the messages imposes a
      AmqpRoutingKey="empty string" (see also https://www.rabbitmq.com/tutorials/tutorial-four-javascript.html
      regarding routing key as empty string). We've tried different
      combinations to create an empty string in the SAP JMS adapter:
      1) JMS.QueueImpl.method.setAmqpRoutingKey java.lang.String ''
      2) JMS.QueueImpl.method.setAmqpRoutingKey java.lang.String ""
      3) JMS.QueueImpl.method.setAmqpRoutingKey java.lang.String ""

      To me 1) seems the correct configuration: see also the xpi inspector log:

      Author's profile photo Christof Johner
      Christof Johner

      In all the combination above the message is successfully sent from
      the SAP PI JMS client but is not written to the queue, thus gets lost.
      The sprkyer (eshop) application retrieves the messages with PHP clients
      and there is also set the AmqpRoutingKey to '', but here the access works.

      The point is now, that the "other" side says, that our SAP PI JMS/Mqrabbit
      client does not properly send the empty string '' (2 single quotes).
      Now we are a bit stuck given the fact we dot have
      more evidencen (xpi inspector log shows no errors, see above).

      1) Do you think for empty routing key the configuration:
      JMS.QueueImpl.method.setAmqpRoutingKey java.lang.String ''
      is correct?

      2) Can we somehow prove that to the "other" side?

      Thanks for your feedback.

      Kind regards
      Christof

      Author's profile photo Christof Johner
      Christof Johner

      PS1: MQrabbit-Server-Konfig with routingkey=<empty string>

      PS: MQrabbit-Server-Konfig with routingkey=sap.customer:

      Author's profile photo Christof Johner
      Christof Johner

      here correct picture with routing key = sap.customer:

      Author's profile photo Christof Johner
      Christof Johner

      PS2: I've just seen your entry in the blog of the 15.6.2018, 8:32am ,
      regarding this very same issue concerning the empty string for
      the parameter 'JMS.QueueImpl.method.setAmqpRoutingKey'.
      So Jordi and you have solved the problem by setting the routingkey
      to a value <> empty string.
      Put in other words: With our SAP PI receiver JMS/mqrabbit adapter
      we cannot send an empty string for the parameter 'JMS.QueueImpl.method.setAmqpRoutingKey'
      and therefore no message can be delivered to a mqrabbit server with a configuration
      where the routing key is defined as empty.

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      I have now finally looked through all your replies. Did you manage to make it working with the routing key being configured (in RabbitMQ) and set (in PO receiver channel)?

      Regards,

      Vadim

      Author's profile photo Christof Johner
      Christof Johner

      Hello Vadim

       

      as a matter of fact it was a bug. SAP provided the following fix:

      SAP Note 2714279 - PI JMS adapter: Empty strings as method parameters are not supported.

       

      Kind regards

      Christof

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      Hi Christof,

      Thank you for sharing this information – good to know it was fixed by the patch.

      Regards,

      Vadim

      Author's profile photo Evgeny Maslenyi
      Evgeny Maslenyi

      Hello Vadim,

       

      Thanks for the interesting  blog.

      Can you please tell me if I can make the routing key dynamic and take it from the message payload?

       

      Author's profile photo Vadim Klimov
      Vadim Klimov
      Blog Post Author

      As to my knowledge, it isn't possible to use dynamic values (for example, those retrieved from message payload or from a dynamic configuration attribute) in additional parameters of a JMS communication channel. Values of additional parameters are static: they shall either contain a parameter value type and the value itself (a more common scenario), or a parameter value type and a reference to a class and a class property, which value shall be used as a parameter value (a less frequent, but supported scenario).