0

I had a working Spring Boot application which uses MQQueueConnectionFactory to initialize a connection to an MQ server.

In my applicationContext.xml I wired a custom configuration class equivalent to this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="mqConfiguration" class="com.myapp.MqConfiguration">
        <property name="host" value="127.0.0.1" />
        <property name="port" value="3005" />
        <property name="username" value="joe" />
        <property name="password" value="mypassword" />
        <property name="queueManager" value="QUEUE_MANAGER_NAME" />
        <property name="channel" value="SERVER_CHANNEL" />
        <property name="sendQueue" value="OUTBOUND_QUEUE_NAME" />
        <property name="receiveQueue" value="INBOUND_QUEUE_NAME" />
    </bean>
</beans>

I was loading the applicationContext via @ImportResource( "classpath:applicationContext.xml")

Everything worked fine and it would send and receive messages via the MQ server.

Then I decided to eliminate my applicationContext.xml (the mqConfiguration bean was the only thing in it, anyway) and move the wiring of MqConfiguration into my application.properties file.

So, my basic strategy was to add the following into my application.properties:

configuration.mq.host="127.0.0.1"
configuration.mq.port="3005"
etc.

And then I removed the ImportResource directive and added the following annotation:

@PropertySources( {
        @PropertySource( value = "classpath:application.properties" )
})

And then, in the MqConfiguration class, I used @Value to wire the application.properties values into the MqConfiguration class, like so:

public class MqConfiguration {
@Value( "${configuration.mq.host}" ) private String host;
@Value( "${configuration.mq.port}" ) private Integer port;
etc.

Upon making this change, suddenly my Java code will not connect to MQ (MQ responds with a MQRC_HOST_NOT_AVAILABLE and my sends and response cause exceptions).

This is very peculiar to me given that I can prove that the MQQueConnectionFactory bean is receiving the values that were provided in application.properties. Take a look at the MQQueueConnectionFactory bean:

public static MQQueueConnectionFactory mqQueueConnectionFactory( MqConfiguration mqConfiguration ) {
        (...ommitted..)
        System.out.println( mqConfiguration.getHost ); // this is 127.0.0.1.. proving we got the value from application.properties
        mqConnectionFactory.setHostName( mqConfiguration.getHost() );
        (...ommitted..)
    }
}

Here is the basic layout of my beans which initialize the connection:

   @Bean
    public static MQQueueConnectionFactory mqQueueConnectionFactory( MqConfiguration mqConfiguration )

    @Bean
    UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter( MQQueueConnectionFactory mqQueueConnectionFactory ) {

    @Bean
    @Primary
    public CachingConnectionFactory cachingConnectionFactory( UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter )

    @Bean
    public JmsOperations jmsOperations( CachingConnectionFactory cachingConnectionFactory )

And here is how I use the JmsOperations object to send and receive:

public Object receiveMessage( MqConfiguration mqConfiguration ) throws JmsException {
    System.out.println( mqConfiguration.getReceiveQueue() ); // this is the proper value: INBOUND_QUEUE_NAME
    return jmsOperations.receiveAndConvert( mqConfiguration.getReceiveQueue() );
}

public boolean sendMessage( String message, MqConfiguration mqConfiguration ) {
    JmsTemplate jmsTemplate = ( JmsTemplate ) jmsOperations;

    System.out.println( mqConfiguration.getSendQueue() ); // this is the proper value: OUTBOUND_QUEUE_NAME
    MQQueue destinationQueue = jmsOperations.execute( executeSession -> MqQueueUtils.resolveQueue( jmsTemplate, executeSession, mqConfiguration.getSendQueue() ) );

    jmsOperations.convertAndSend( destinationQueue, message );

    return true;
}

Any thoughts on this one? It seems unbelievable that switching wiring via application.properties vs. applicationContext.xml would make any difference, especially if the same actual values are coming in from either source. But somehow I can not escape the conclusion that something with the MQ connection is getting messed up when the same values come from application.properties.

JoshMc
  • 10,239
  • 2
  • 19
  • 38
Mark Nenadov
  • 6,421
  • 5
  • 24
  • 32
  • I believe the default in IBM MQ Classes for JMS for host is 127.0.0.1 assuming this is not just you sanitizing the IP addresses try specifying a different IP in `configuration.mq.host` and compare to against `mqConfiguration.getHost`. If this is just a example IP and the real IP is not 127.0.0.1, the please ignore. – JoshMc Sep 26 '17 at 23:45
  • @JoshMc the custom class I am wiring (mqConfiguration) with the field "host" does not have a default and based on the println shown is confirmed to be receiving the 127.0.0.1 from the properties file. – Mark Nenadov Sep 27 '17 at 19:43
  • Can you provide a full linked exception? Sometimes those provide more information than just the basic `MQRC`. Also can you see if the queue manager's `AMQERR01.LOG` has any entries when you attempt to connect? – JoshMc Sep 27 '17 at 22:16
  • Mark, did you figure out what the issue was? – JoshMc Oct 02 '17 at 18:46
  • Hi Josh, thanks for following up. I had to revert to meet a deadline.There was nothing in AMQERR01.LOG. I no longer have the exception stacktrace handy, but I'm pretty sure it was just a plain vanilla MQRC_HOST_NOT_AVAILABLE stacktrace that gets thrown when you have the wrong IP. – Mark Nenadov Oct 03 '17 at 19:15

0 Answers0