I am trying to configure the OpenLiberty 18.0.0.2 to use embedded messaging for sending some simple JMS messages.
My current server.xml
looks like the following:
<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">
<featureManager>
<feature>javaee-8.0</feature>
<feature>mpConfig-1.2</feature>
<feature>mpMetrics-1.1</feature>
<feature>wasJmsServer-1.0</feature>
<feature>wasJmsClient-2.0</feature>
<feature>localConnector-1.0</feature>
</featureManager>
<quickStartSecurity userName="admin" userPassword="adminpwd" />
<httpEndpoint id="defaultHttpEndpoint" httpPort="9080" httpsPort="9443" />
<applicationManager autoExpand="true" />
<applicationMonitor updateTrigger="mbean" />
<messagingEngine>
<queue id="QUEUE1" />
</messagingEngine>
<jmsQueueConnectionFactory jndiName="jms/JmsFactory">
<properties.wasJms remoteServerAddress="localhost:7276:BootStrapBasicMessaging" />
</jmsQueueConnectionFactory>
<jmsQueue jndiName="jms/JmsQueue">
<properties.wasJms queueName="QUEUE1" />
</jmsQueue>
</server>
And my JMS sender looks like the following:
public class JmsMessageSender {
@Resource(mappedName = "jms/JmsFactory")
private ConnectionFactory jmsFactory;
@Resource(mappedName = "jms/JmsQueue")
private Queue jmsQueue;
public void send() {
TextMessage message;
try (Connection connection = jmsFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(jmsQueue)) {
message = session.createTextMessage();
message.setText("Hello World!");
producer.send(message);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
When I am running my application I get the following exception when I am trying to send the message to the embedded messaging queue:
javax.jms.InvalidDestinationException: CWSIA0281E: The specified value null is not allowed for Destination.
[err] at com.ibm.ws.sib.api.jms.impl.JmsDestinationImpl.checkNativeInstance(JmsDestinationImpl.java:993)
[err] at [internal classes]
It looks like my code can't obtain the queue destination through JNDI
. Did I configure embedded messaging incorrectly or is the error in my source code?
UPDATE 1:
I updated the source code so that I won't pass the destination to the .send()
method an now I am getting the following error on startup:
[ERROR ] cdi.resource.injection.error.CWOWB1000E
CWNEN0030E: The server was unable to obtain an object instance for the java:comp/env/de.rieckpil.blog.JmsMessageSender/jmsQueue reference.
The exception message was: CWNEN1004E: The server was unable to find the de.rieckpil.blog.JmsMessageSender/jmsQueue default binding with the javax.jms.Queue type for the java:comp/env/de.rieckpil.blog.JmsMessageSender/jmsQueue reference.
UPDATE 2:
Sending the message now works, but I am unable to receive the message. My message driven bean looks like the following (the feature mdb-3.2
is enabled):
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destination",
propertyValue = "jms/JmsQueue"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue")
})
public class JmsMessageReader implements MessageListener {
@Override
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("Message arrived: " + textMessage.getText());
} catch (JMSException e) {
System.err.println(e.getMessage());
}
}
}
EDIT: Update after comment that there was an issue with resource injection
First, fix the JMS API usage to only pass in the destination once (not on both createProducer()
and send()
. Otherwise you may experience a CWSIA0066E failure.
Second, change the @Resource
attributed from mappedName to lookup
@Resource(lookup = "jms/JmsFactory")
private ConnectionFactory jmsFactory;
@Resource(lookup = "jms/JmsQueue")
private Queue jmsQueue;
public void send() {
TextMessage message;
try (Connection connection = jmsFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(jmsQueue)) {
message = session.createTextMessage();
message.setText("Hello World!");
// Don't pass in destination again since you set it in createProducer()
producer.send(message);
// ...
@Resource
injectionFinally, @Resource
injection isn't going to work in any old POJO, but only in special classes that are scanned by the container. Try moving the injection to a servlet, EJB, or CDI managed bean.
Though I can see why you would have thought to call this "embedded MQ", the "messaging engine" you're using here is provided by what is actually called Liberty embedded messaging.
It is also a JMS provider. That is, it implements the JMS API, as does MQ, the other IBM-provided JMS provider that can be used in Liberty.