Spring how do I create multiple queries with different vpnMsg values

vince92079
vince92079 Member Posts: 5
edited January 2020 in Connectors & Integrations #1

I'm relatively new to JMS and Solace. I'm trying to create a Spring application that is using JMS Solace to connect to a Solace broker that has multiple subscriptions. Each of the subscriptions has a different msgVPN and queue value. I was able to use solace-jms-spring-boot-starter to create a connection to one queue. The problem is when I try to create a second queue on the same connection I get a Solace 503 error 'Unknown Queue' error.

Ideally in my head, this appcliation would have one JMS connection with several queues to retrieve messages from all the subscriptions. Is this possible with Solace/Spring or is there another way I need to do this?

Currently, this is how I am trying to make the connection.

BeanConfig.java

import com.acme.listener.JmsExceptionListener;
import com.acme.listener.JmsMessageListener;
import com.solacesystems.jms.SolConnectionFactory;
import com.solacesystems.jms.SolJmsUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import javax.jms.Connection;
import javax.jms.MessageConsumer;
import javax.jms.Queue;

@Configuration
@PropertySource({"classpath:application.properties"})
public class BeanConfig {

    private static final Logger logger = LoggerFactory.getLogger(BeanConfig.class);

    @Autowired
    private Environment environment;

    @Autowired
    private JmsExceptionListener exceptionListener;

    @Bean
    public SolConnectionFactory solConnectionFactory() throws Exception {
        SolConnectionFactory connectionFactory = SolJmsUtility.createConnectionFactory();
        connectionFactory.setHost(environment.getProperty("solace.java.host"));
        // Here I have to set the connection to a msgVPN value. 
        // From everything I've seen the VPN needs to be set here.
        connectionFactory.setVPN(environment.getProperty("solace.java.msgVpn"));
        connectionFactory.setUsername(environment.getProperty("solace.java.clientUsername"));
        connectionFactory.setPassword(environment.getProperty("solace.java.clientPassword"));
        connectionFactory.setClientID(environment.getProperty("solace.java.clientName"));
        return connectionFactory;
    }

    @Bean
    public JmsMessageListener jmsMessageListener() {
        return new JmsMessageListener();
    }

    @Bean(destroyMethod = "close")
    public Connection connection() {
        Connection connection = null;
        javax.jms.Session session;

        try {
            connection = solConnectionFactory().createConnection();
            session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);

            // This queue will work and return messages because the connection has a vpn msg value set correctly 
            Queue queue = session.createQueue(environment.getProperty("Queue1.solace.message.consumer.queue"));
            MessageConsumer messageConsumer = session.createConsumer(queue);
            messageConsumer.setMessageListener(jmsMessageListener());

            // Adding this queue will not work and crash the app because the connection is set to the other queue via the connection's msgVPN value
            Queue FDPSQueue = session.createQueue(environment.getProperty("Queue2.solace.message.consumer.queue"));
            MessageConsumer messageConsumer1 = session.createConsumer(FDPSQueue);
            messageConsumer1.setMessageListener(jmsMessageListener1());

            connection.setExceptionListener(exceptionListener);
            // Application fails here with a Solace 503 error
            connection.start();
            logger.info("Connected Awaiting message...");

        } catch (Exception e) {
            logger.info("JMS connection failed with Solace." + e.getMessage());
            e.printStackTrace();
        }
        return connection;
    }

}

`
application.properties

Queue1.solace.message.consumer.queue=acme.queue1.OUT
Queue2.solace.message.consumer.queue=acme.queue2.OUT
solace.java.host=tcps://:
solace.java.clientUsername=
solace.java.clientPassword=
solace.java.msgVpn=msgVPN1
solace.java.clientName=solacetest
solace.java.messageAckMode=client_ack
solace.java.reapplySubscriptions=false

Tagged:

Answers

  • Hi Vince, each messaging-VPN is a separate virtual EventBroker, specifically for separation and security. You will need different connections to communicate on different msg-VPNs just as you would with different physical brokers.

    If you want one connection to communicate with clients on both, perhaps you really want one msg-VPN? If you are looking for a way to logically separate communications you can do use hierarchical topics and topic-to-queue subscriptions.

  • vince92079
    vince92079 Member Posts: 5

    I suspected that could be the case. My application is trying to connect to a broker that exists outside of my control. All I have are the solace credentials to connect to them so I'm going to have to use a separate connection for each. Thank you for the information.

    Do you happen to know of a code example that shows how to create multiple Connections using Spring or just in general? The class I posted doesn't lend itself well to doing that. I've been searching for some time and had no success.

  • vince92079
    vince92079 Member Posts: 5

    Never mind I think I have it. I was able to create another @Bean public Connection connection2() method that took a separate configuration from my applications.properties and was able to have it connect to the second queue while the first queue was running.

  • RobO
    RobO Member, Employee Posts: 19 Solace Employee

    Is there a reason you need to manage multiple connections within the same application? Do you need to correlate the messages from the different queues together? Could you just run multiple instances of the app, passing in a different application.configuration file that contains the different msg vpn and queue name? This way each instance is isolated to the specific VPN/Connection/Queue.

  • vince92079
    vince92079 Member Posts: 5

    @RobO said:
    Is there a reason you need to manage multiple connections within the same application? Do you need to correlate the messages from the different queues together? Could you just run multiple instances of the app, passing in a different application.configuration file that contains the different msg vpn and queue name? This way each instance is isolated to the specific VPN/Connection/Queue.

    Yes that idea was something I considered but couldn't do. Most of these messages need to be changed into SolrDocument objects to be ingested into Apache Solr and can't be generic enough for the messages of all five feeds. There's one core for each feed. So for now I have to make specific objects for each feed. This is for a proof of concept so I may be able to alter the architecture if I get more time to develop this further.

  • RobO
    RobO Member, Employee Posts: 19 Solace Employee

    @vince92079 said:
    Yes that idea was something I considered but couldn't do. Most of these messages need to be changed into SolrDocument objects to be ingested into Apache Solr and can't be generic enough for the messages of all five feeds. There's one core for each feed. So for now I have to make specific objects for each feed. This is for a proof of concept so I may be able to alter the architecture if I get more time to develop this further.

    I believe I know the 5 feeds you are referring to. You have FDPSQueue in your code sample which gave it away :smile: If we are talking about the SWIM feeds, yes they are drastically different. Something I did with the same feeds was to create a consumer using Spring Integration and the HeaderValueRouter (keyed on DEX_SOURCE_TYPE) (but could also do the same thing with Apache Camel or even write your own with a case statement) and then routed the message to a "handler" that handles the specific type of message. Yes you have to create specific objects (handlers) for each message type, there is no way around that. But you can design the app to route based on a header value or even payload if you wanted. I ran multiple instances of the app, one to each feed. But the app was the same code just different configuration files. Just an idea.

  • vince92079
    vince92079 Member Posts: 5

    I really need to go over my code samples better when I post questions lol.
    Thank you for the information.