Quarkus ActiveMQ JMS - java

I have an ActiveMQ queue that does seem not seem to be supported by Quarkus. When I try to use the Quarkus JMS implementation described here I get the following error:
AMQP SASL header mismatch value 0, expecting 41. In state: HEADER0
I assume that this is because the ActiveMQ server does not support AMQP. The code I wrote to try and connect to the ActiveMQ server.
ConnectionFactory connectionFactory = new ConnectionFactory();
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("inQue");
producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
messageMap = session.createMapMessage();
While the above does not work. If i change it to using
ActiveMQConnectionFactory from ActiveMQ it works just fine:
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
connection = connectionFactory.createConnection("admin", "admin");
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("inQue");
producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
messageMap = session.createMapMessage();
But if i change to the Quarkus version of ConnectionFactory it no longer works and I get the error above. So is it possible to solve this somehow? Or do I need to use ActiveMQConnectionFactory? If so, how can I get Quarkus to register my MessageListener? Right now, just to test, I write:
MessageListener listener = new MyListener();
consumer.setMessageListener(listener);
But I would like Quarkus to do this when the application starts. But I'm not sure how to do it.

Depending on which version of ActiveMQ you are using you should be able to use the Quarkus JMS extension which is based on Qpid JMS and speaks AMQP. The trick is that you need to connect to the transport connector that was configured to speak AMQP and not one that uses the native Openwire protocol which normally resides on port 61616.
The ActiveMQ documentation defines how this is done. Essentially in your broker configuration you need a definition similar to this:
<transportConnectors>
<transportConnector name="amqp" uri="amqp://0.0.0.0:5672"/>
</transportConnectors>
Of course if using ActiveMQ Artemis this configuration would be different but you didn't specify which specific version of ActiveMQ you are running.
The error message you provided (If it is from the server logs) indicates that the client did indeed connect to an AMQP endpoint but it got something that it did not expect which implies something else strange is going on such as you are not using Qpid JMS but some other client since the initial byte of the expected AMQP header is reported to have been zero which is definitely wrong since an AMQP header always starts with the letter 'A'.
NOTE: Given the comments the error message in the question is likely from the client which would indicate the client read the normally sent Openwire header meaning the transport connector in play was an Openwire variant.

Related

Avoiding error messages in connecting to active/passive ActiveMQ

I am creating a program to send messages to ActiveMQ. This server is in active/passive configuration with one active and two standby nodes.
My code for creating connections as follows:
String furl = "failover:(tcp://aa.myamq-01:61616:tcp://aa.myamq-02:61616:tcp://aa.myamq-03:61616");
ConnectionFactory = new ActiveMQConnectionFactory(furl);
Connection connection = ConnectionFactory.createConnection();
connection.start();
Everything works as expected. However I get the following output in the console.
ERROR | Connect fail to tcp://aa.myamq-01:61616, error message : Connection refused:Connect
ERROR | Connect fail to tcp://aa.myamq-02:61616, error message : Connection refused:Connect
INFO |Successfully connected to tcp://aa.myamq-03:61616
Is there a way the active server can be identified and connection attempted to it only? Alternatively, can the error messages be suppressed?
AFAIK there isn't in this scenario. Inactive ActiveMQ nodes are actually not accepting connections. Therefor they look like they are down.
But if you would need to find out which node is master you can find that in DB if you use DB backend in ActiveMQ.
Regarding suppressing this message I would not even try to do that because if there would be a regular failure you will not notice it.

How to timeout queueConnectionFactory create connection

I'm facing a timeout while invoking javax.jms.QueueConnectionFactory.createQueueConnection()
¿Is there any way to customize timout time for creating connection?
javax.jms.QueueConnectionFactory connectionFactory; //look up in context here
connectionFactory.createConnection();
This depends to how you connect to jms, for spring you can see How to set waiting timeout on JmsMessagingTemplate.sendAndReceive for ibm mq IBM MQ Connect Factory CLIENTRECONNECTTIMEOUT without using CLIENTRECONNECTOPTIONS

javax.jms.JMSException: Cannot send to a non-connected transport

I am using the qpid-jms-client.jar library to form a connection with a broker.
My code is ::
Properties properties = new Properties();
properties.load(this.getClass().getResourceAsStream("jndi.properties"));
Context context = new InitialContext(properties);
System.setProperty("javax.net.ssl.trustStore", "C:/Users/xxxxx/qpid.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "test123");
ConnectionFactory factory = (ConnectionFactory) context.lookup("myFactoryLookup");
Destination queue = (Destination) context.lookup("myQueueLookup");
Connection connection = factory.createConnection("<my-username>", "<my-password>");
connection.setExceptionListener(new MyExceptionListener());
connection.start();
My jndi.properties file is ::
java.naming.factory.initial=org.apache.qpid.jms.jndi.JmsInitialContextFactory
connectionfactory.myFactoryLookup=amqps://esesslx0100.se:9443
queue.myQueueLookup=emft_input
topic.myTopicLookup=topic
destination.topicExchange=amq.topic
jms.user=test
Now the above code gives me the ERROR ::
Connection ExceptionListener fired, exiting.
javax.jms.JMSException: Cannot send to a non-connected transport.
at org.apache.qpid.jms.exceptions.JmsExceptionSupport.create(JmsExceptionSupport.java:66)
at org.apache.qpid.jms.exceptions.JmsExceptionSupport.create(JmsExceptionSupport.java:88)
at org.apache.qpid.jms.JmsConnection.onAsyncException(JmsConnection.java:1188)
at org.apache.qpid.jms.JmsConnection.onConnectionFailure(JmsConnection.java:1104)
at org.apache.qpid.jms.provider.amqp.AmqpProvider.fireProviderException(AmqpProvider.java:847)
at org.apache.qpid.jms.provider.amqp.AmqpProvider.pumpToProtonTransport(AmqpProvider.java:820)
at org.apache.qpid.jms.provider.amqp.AmqpProvider.access$300(AmqpProvider.java:90)
at org.apache.qpid.jms.provider.amqp.AmqpProvider$16.run(AmqpProvider.java:683)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Cannot send to a non-connected transport.
at org.apache.qpid.jms.transports.netty.NettyTcpTransport.checkConnected(NettyTcpTransport.java:279)
at org.apache.qpid.jms.transports.netty.NettyTcpTransport.allocateSendBuffer(NettyTcpTransport.java:176)
at org.apache.qpid.jms.provider.amqp.AmqpProvider.pumpToProtonTransport(AmqpProvider.java:806)
... 9 more
Since the broker is configures with SaSL, I am also providing my username and password. I am currently unaware of why this ERROR occurs. Ive looked around on the internet but there is no clear explanation as to why it would occur with qpid. Any ideas why this ERROR occurs ?
My trustStore file is correct since I have verifies SSL connectivity using it.
Turning up the clients logging might give some more trace/debug information. Both the 'regular logging', and 'protocol trace logging' (if it even gets that far) might be useful. See http://qpid.apache.org/releases/qpid-jms-0.22.0/docs/index.html#logging for more details.
To the issue here, where it seems the TCP connection is being cut, the server logs could also perhaps be useful in giving a reason.
You dont mention which server you are using here, but have mentioned ActiveMQ and RabbitMQ in other related questions. Its unclear how far the connection gets, but if the server is RabbitMQ, one potential explanation might also be: https://github.com/rabbitmq/rabbitmq-amqp1.0/issues/47. As mentioned in another answer, this may not matter due to other issues, e.g. I didn't have much success using the JMS client or some other AMQP 1.0 clients against RabbitMQ previously due to an issue I reported which stops them in their tracks when creating consumers and producers: https://github.com/rabbitmq/rabbitmq-amqp1.0/issues/34
Thanks for all your replies. In my case turns out all the libraries/configurations I was using were indeed correct. I contacted the team that manages the broker. Turns out the user I was trying to connect with had some PRIVILEGE issues. As soon as they gave my user the correct rights, I was able to form a successful connection and transmit and receive messages.
In my case when receiving this error it was simply because when I was in the office our company proxy was filtering this traffic out when I executed programatically. Using Service Bus Explorer still worked though as it must have picked up machine settings that add the proxy.
We were using a publicly hosted Service Bus so I attempted from my home network without the proxy and everything worked as expected. Using Wireshark or similar program probably would have helped identify this quicker. Hope this helps someone.
This line shows your error:
Caused by: java.io.IOException: Cannot send to a non-connected transport.
That's saying your connection is configured incorrectly. One thing I see is that your're not referencing the properties in your property file. For example,
this:
ConnectionFactory factory = (ConnectionFactory) context.lookup("myFactoryLookup");
Destination queue = (Destination) context.lookup("myQueueLookup");
Should probably be this:
ConnectionFactory factory = (ConnectionFactory) context.lookup("connectionfactory.myFactoryLookup");
Destination queue = (Destination) context.lookup("queue.myQueueLookup");

Unacked message if RabbitMQ server restarts in between the consumer consumes message

I am using Spring AMQP and this is my connection factory code:
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setAcknowledgeMode(AcknowledgeMode.AUTO);<br/>
factory.setDefaultRequeueRejected(false);
During consuming the message if RabbitMQ server restarts or there is a connection lost I will get the below exception:
org.springframework.amqp.rabbit.connection.AutoRecoverConnectionNotCurrentlyOpenException: Auto recovery connection is not currently open
If server comes up my application will be connected again
but with a new connection and there will be an unacked messsage.
How to handle this? I want the message to be requeued and my old connection should be killed.
Consider to use the latest Spring AMQP 1.7.2 which turns off that:
connectionFactory.setAutomaticRecoveryEnabled(false);
on the target com.rabbitmq.client.ConnectionFactory in favor of its own recovery mechanism.

Weblogic jms distributed topic

Using java application, I'm trying to create a durable subscription on a jms uniform distributed topic.
The jms server is running on weblogic 10.3.5 and the topic is distributed on 2 servers.
If I'm developping a message driven bean, it's working. I have a durable subscription on both servers with the same subscription name.
With a standalone java application, I can do the job with a normal topic (not distributed). But can't manage it to work with distributed topic.
InitialContext ic = new InitialContext();
TopicConnectionFactory connectionFactory = (TopicConnectionFactory) ic.lookup("myConnectionFactory");
TopicConnection connection = connectionFactory.createTopicConnection();
connection.setClientID("testclient");
TopicSession session = connection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber;
Topic topic1 = (Topic) ic.lookup("jmsserver1#myTopic");
Topic topic2 = (Topic) ic.lookup("jmsserver2#myTopic");
subscriber = session.createDurableSubscriber(topic1,"testSubscription","",false);
subscriber = session.createDurableSubscriber(topic2,"testSubscription","",false);
Gives me
Exception in thread "main" weblogic.jms.common.JMSException: [JMSClientExceptions:055037]Subscription testSubscription is in use
In the weblogic console the first subscription testSubscription on myJmsModule!jmsserver1#myTopic is created not the second.
What can I do ?
You will have to remove the durable subscription manually and WLS will not remove to automatically
https://docs.oracle.com/cd/E17904_01/web.1111/e15493/dist_topics.htm#WLMDB10013
Setting Automatic Deletion of Durable Subscriptions :-
You can configure an MDB to automatically delete a durable topic subscription when the MDB is undeployed or deleted from a server. To configure an MDB to automatically delete durable topic subscriptions, set durable-subscription-deletion to True. By default, durable-subscription-deletion is set to False
By default it is false and thus it will not clear the durable subscriber automatically.
You need to change the ConnectionFactory via the weblogic admin console to create shareable connections
Client ID Policy: CLIENT_ID_POLICY_UNRESTRICTED
Subscription Sharing Policy:Sharable
https://docs.oracle.com/cd/E57014_01/wls/WLACH/pagehelp/JMSjmsconnectionjmsconnectionfactoryconfigclientparamstitle.html

Categories

Resources