MessageDrivenBean isnt handle messages [Wildfly] - java

Im trying to develop a "Message Driven Bean" to handle all the local ActiveMQ messages, but it's the first time that i try to do something like this.
The most part of the material that i found explain how to write a MDB using JBOSS server, in this case there's a xml file with some queue information, but in all wildfly tutorials there's no mention to any kind of configuration like that.
I have the following scenario:
A simple java project like message producer
An ActiveMQ instance running local
An EJB project deployed into Wildfly 10
My producer project is able to send messages to ActiveMQ queue, this part its working,but my EJB project just have a single class called TestMDBHandle with #MessageDriven annotation. Is this enough to receive my queue messages? Because the MDB isnt working, i imagine must be a kind of configuration or property in EJB to specify the host of the message-broker.
My message producer:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class MessageSender {
public static void main(String args[]) throws NamingException, JMSException {
MessageSender sender = new MessageSender();
sender.sender();
}
public void sender() throws NamingException, JMSException {
InitialContext jndi = null;
Session session = null;
Connection connection = null;
try {
jndi = new InitialContext();
ConnectionFactory factory = (ConnectionFactory)jndi.lookup("connectionFactory");
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = (Destination)jndi.lookup("MyQueue");
MessageProducer producer = session.createProducer(destination);
TextMessage mensagem = session.createTextMessage("Eu enviei uma mensagem!");
producer.send(mensagem);
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
connection.close();
jndi.close();
}
}
}
My jms properties located inside my producer project
java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory
java.naming.provider.url=tcp://localhost:61616
connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactory
queue.MyQueue=jms/myqueue
Finally, my ejb project have this single class, without any kind of property file or xml.
package br.com.jms.mdb;
import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
#MessageDriven(name = "meuHandler", activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/myqueue") })
public class Teste implements MessageListener {
#Resource
private MessageDrivenContext mdctx;
public Teste() {
}
#Override
public void onMessage(Message message) {
TextMessage objectMessage = null;
try {
objectMessage = (TextMessage)message;
System.out.println("Achei a mensagem : " + objectMessage.getText().toString());
}catch(JMSException e) {
e.printStackTrace();
}
}
}

Maybe you can provide a little more information such as the xml file with the queue information and the annotation properties of the MDB? Because it sounds you are heading in the right direction. The two main things:
You have to specify the exact queue that the MDB is listening to, for example through the properties of the #MessageDriven annotation (such as "name", "mappedName", "activationConfig"). And of course override the onMessage() method to process the messages.
You also have to make sure that this specific queue is available as a resource for your application. You have to provide jms configuration for this, which also defines the resource type (Queue or Topic). From your question I can't tell which of these steps you have (partly) completed.

Related

Redhat Fuse-Karaf refusing to inject jms ConnectionFactory

Fuse karaf fuse-karaf-7.11.1.fuse-7_11_1-00013-redhat-00003.
I am creating a simple bridge from servlet to ActiveMQ 5.9 using amqp protocol. I managed to configure a ConectionFactory and tested OK with the jms:send command. I wrote a JMS service which is responding to the POST from the servlet side, but is failing to create the Connection factory.
admin#root()> jms:connectionFactories
JMS Connection Factory
jms/artemis
The Jms service code is:
package com.mycompany.jms;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TemporaryQueue;
import javax.jms.TextMessage;
import javax.naming.*;
import org.apache.aries.blueprint.annotation.service.Reference;
import org.apache.aries.blueprint.annotation.service.Service;
import org.apache.aries.blueprint.annotation.service.ServiceProperty;
import com.mycompany.JmsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Service(classes = JmsService.class, properties = {
// Only necessary for Remote Services
#ServiceProperty(name = "service.exported.interfaces", values = "*") })
#Singleton
public class JmsService4Reals implements JmsService {
private static final Logger LOG = LoggerFactory.getLogger(JmsService4Reals.class);
#Reference
ConnectionFactory connectionFactory;
#Override
public String sendMessage(String opeCod, String message) {
LOG.info(String.format("received: opeCod=%s, msg=%s", opeCod, message));
try {
if(connectionFactory== null)
return "Reference: no connectionFactory found";
Connection connection = null;
try {
connection = connectionFactory.createConnection();
LOG.info("JMS Connection created=%s", connection);
connection.start();
} catch (JMSException e) {
if (connection != null)
connection.stop();
return prepareErrorResponse(e.getMessage());
}
} catch (JMSException e) {
return prepareErrorResponse(e.getMessage());
}
}
private String prepareErrorResponse(String msg) {
return msg;
}
}
Please help, i'm stuck with no progress
The servlet always reponds with "Reference: no connectionFactory found"
I also tried with the JNDI lookup method with the same result.
try {
Context context = new InitialContext();
LOG.info("context=%s", context);
connectionFactory = (ConnectionFactory) context.lookup("jms/artemis");
LOG.info("connectionFactory=%s", connectionFactory);
}catch(Exception e) {
e.printStackTrace();
return "no connectionFactory found on JNDI";
}
I expect the jms/artemyour textis to be injected on my ConnectionFactory, but never occurs.
The actual exception you get when calling context.lookup() is:
javax.naming.NoInitialContextException: \
Need to specify class name in environment or system property, \
or as an applet parameter, or in an application resource file: \
java.naming.factory.initial
That's how JNDI works and you need special preparation to use it in OSGi (and Fuse Karaf is OSGi runtime based on Apache Karaf).
You have to install jndi feature first. Then your exception will be:
javax.naming.NotContextException: jms/artemis
However it's almost everything you need. jndi feature gives you several commands, like this one:
karaf#root()> jndi:names
JNDI Name │ Class Name
─────────────────────────┼─────────────────────────────────────────────────────────────────
osgi:service/jms/artemis │ org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory
osgi:service/jndi │ org.apache.karaf.jndi.internal.JndiServiceImpl
If you now use osgi:service/jms/artemis instead of just jms/artemis, you get proper connection factory. I got this in logs:
2023-01-02 09:45:53,412 INFO {XNIO-2 task-1} [grgr.test.Activator7$1.doGet()] \
(Activator7.java:65) : connectionFactory=ActiveMQConnectionFactory [serverLocator=ServerLocatorImpl \
[initialConnectors=[TransportConfiguration(name=null, factory=org-apache-activemq-artemis-core-remoting-impl-netty-NettyConnectorFactory) \
?port=61616&host=localhost], discoveryGroupConfiguration=null], \
clientID=null, consumerWindowSize = 1048576, \
dupsOKBatchSize=1048576, transactionBatchSize=1048576, readOnly=falseEnableSharedClientID=false]
You can find more examples of persistence usage in Fuse Karaf here: https://github.com/jboss-fuse/karaf-quickstarts
A developer documentation is here: https://github.com/jboss-fuse/karaf-quickstarts/tree/7.x.redhat-7-11-x/persistence/manual/src/main/asciidoc

Qpid and JNDI for encrypted messages

I'm currently working on a JMS project and I have created 2 keys and 2 certificates as well as a TrustStorage, mytruststore which I created through Qpid's UI.
In my jndi.properties file I have the following code:
//Set the InitialContextFactory class to use
java.naming.factory.initial = org.apache.qpid.jms.jndi.JmsInitialContextFactory
//Define the required ConnectionFactory instances
//connectionfactory.<JNDI-lookup-name> = <URI>
connectionfactory.myFactoryLookup = amqp://localhost:5672
connectionfactory.producerConnectionFactory = amqp://admin:admin#?brokerlist='tcp://localhost:5672?encryption_remote_trust_store='$certificates%255c/mytruststore''
connectionfactory.consumer1ConnectionFactory = amqp://admin:admin#?brokerlist='tcp://localhost:5672?encryption_key_store='C:\OpenSSL-Win64\bin\mytruststorage.jks'&encryption_key_store_password='thanos''
connectionfactory.consumer2ConnectionFactory = amqp://admin:admin#?brokerlist='tcp://localhost:5672?encryption_key_store='C:\OpenSSL-Win64\bin\mytruststorage.jks'&encryption_key_store_password='thanos''
//Configure the necessary Queue and Topic objects
//queue.<JNDI-lookup-name> = <queue-name>
//topic.<JNDI-lookup-name> = <topic-name>
queue.myQueueLookup = queue
topic.myTopicLookup = topic
queue.myTestQueue = queue
In my EncryptionExample.java class I have the following code:
package org.apache.qpid.jms.example;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class EncryptionExample {
public EncryptionExample() {
}
public static void main(String[] args) throws Exception {
EncryptionExample encryptionExampleApp = new EncryptionExample();
encryptionExampleApp.runProducerExample();
encryptionExampleApp.runReceiverExample();
}
private void runProducerExample() throws Exception
{
Connection connection = createConnection("producerConnectionFactory");
try {
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
Destination destination = createDesination("myTestQueue");
MessageProducer messageProducer = session.createProducer(destination);
TextMessage message = session.createTextMessage("Hello world!");
// ============== Enable encryption for this message ==============
message.setBooleanProperty("x-qpid-encrypt", true);
// ============== Configure recipients for encryption ==============
message.setStringProperty("x-qpid-encrypt-recipients", "CN=client1, OU=Qpid, O=Apache, C=US");
messageProducer.send(message);
session.commit();
}
finally {
connection.close();
}
}
private void runReceiverExample() throws Exception
{
Connection connection = createConnection("consumer1ConnectionFactory");
try {
connection.start();
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
Destination destination = createDesination("myTestQueue");
MessageConsumer messageConsumer = session.createConsumer(destination);
Message message = messageConsumer.receive();
if (message instanceof TextMessage) {
// application logic
System.out.println(((TextMessage) message).getText());
} else if (message instanceof BytesMessage) {
// handle potential decryption failure
System.out.println("Potential decryption problem. Application not in list of intended recipients?");
}
session.commit();
}
finally {
connection.close();
}
}
///////////////////////////////////////
// The following is boilerplate code //
///////////////////////////////////////
private Connection createConnection(final String connectionFactoryName) throws JMSException, IOException, NamingException
{
try (InputStream resourceAsStream = getResourceAsStream("jndi.properties")) {
Properties properties = new Properties();
properties.load(resourceAsStream);
Context context = new InitialContext(properties);
ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup(connectionFactoryName);
final Connection connection = connectionFactory.createConnection();
context.close();
return connection;
}
}
private InputStream getResourceAsStream(String string) {
// TODO Auto-generated method stub
return null;
}
private Destination createDesination(String desinationJndiName) throws IOException, NamingException
{
try (InputStream resourceAsStream = this.getClass().getResourceAsStream("example.properties")) {
Properties properties = new Properties();
properties.load(resourceAsStream);
Context context = new InitialContext(properties);
Destination destination = (Destination) context.lookup(desinationJndiName);
context.close();
return destination;
}
}
}
When I'm trying to build it I get the following exceptions.
Exception in thread "main" java.lang.NullPointerException
at java.util.Properties$LineReader.readLine(Unknown Source)
at java.util.Properties.load0(Unknown Source)
at java.util.Properties.load(Unknown Source)
at
org.apache.qpid.jms.example.EncryptionExample.createConnection(EncryptionExample.java:106)
at
org.apache.qpid.jms.example.EncryptionExample.runProducerExample(EncryptionExample.java:54)
at org.apache.qpid.jms.example.EncryptionExample.main(EncryptionExample.java:48)
I assume that something's wrong with the following code in jndi.properties file:
connectionfactory.myFactoryLookup = amqp://localhost:5672
connectionfactory.producerConnectionFactory = amqp://admin:admin#?brokerlist='tcp://localhost:5672?encryption_remote_trust_store='$certificates%255c/mytruststore''
connectionfactory.consumer1ConnectionFactory = amqp://admin:admin#?brokerlist='tcp://localhost:5672?encryption_key_store='C:\OpenSSL-Win64\bin\mytruststorage.jks'&encryption_key_store_password='thanos''
connectionfactory.consumer2ConnectionFactory = amqp://admin:admin#?brokerlist='tcp://localhost:5672?encryption_key_store='C:\OpenSSL-Win64\bin\mytruststorage.jks'&encryption_key_store_password='thanos''
This is my solution Explorer:
This first and biggest problem you have is that you are trying to use connection URIs and client features from a client other than the one you have configured you project to use. You seem to be using Qpid JMS which is the new AMQP 1.0 client developed at the Qpid project. This client uses a different URI syntax that the previous AMQP 0.x clients and you will get exception from the connection factory when passing in these invalid URIs.
The other problem you will have (which was called out in the comments on your post) is that there is not message encryption feature in the AMQP 1.0 JMS client so that would be your next problem once you got the URIs correctly defined.
The documentation for the newer AMQP 1.0 JMS client is here.
You cannot use // for comments in Properties files. Use # or ! instead.
See: https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader-

not able to Log the message in activemq using log4j2

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Producer {
private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
private static String QUEUE_NAME = "kesaven";
private static final Logger logger = LogManager.getLogger(Producer.class.getName());
public static void main(String[] args) throws JMSException
{
//System.out.println(url);
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(QUEUE_NAME);
MessageProducer producer = session.createProducer(destination);
//TextMessage message = session.createTextMessage("My first log message to queue");
logger.info("My first log message to queue");
//producer.send(message);
//System.out.println("Sentage '" + message.getText() + "'");
connection.close();
}
}
i am trying to log the message to a queue using log4j2 and activemq. i am using log4j2.3 and for queue i am using activemq 5.9.0 . i am able to see exception message in queue not the message i sent. Following is the error message in queue
javax.jms.JMSException: Failed to build body from content.
Serializable class not available to broker. Reason:
java.lang.ClassNotFoundException:
org.apache.logging.log4j.core.impl.Log4jLogEvent$LogEventProxy
What appender are you using to write the data to ActiveMQ? I would suggest that instead of using Java serialization to write the log event that you serialize it to JSON, use the RFC5424 layout or some other format that doesn't require the Log4j2 jars when reading the events.
Since the Log4event is put on the queue , can you check if you have the log4j2 jars available on the broker end.
I added the following jars from log4j2 to the activeMQ server /lib directory to make this work
log4j-api-2.6.1,
log4j-core-2.6.1
I logged Strings only, if I tried to log ObjectMessages, the queue entry would not open in the Queue manager view, the JSP failed.

The method createConnection() is undefined for the the class ConnectionFactory

I have been trying to learn ActiveMQ and JMS. When I compile the following code I get the above exception. Although, I have attached the right jar files for JMS and ActiveMQ. Eclipse asks me to add a cast to the ConnectionFactory object when I try to create a connection (i.e. connectionFactory.createConnection()) using the ConnectionFactory object. The codes that I see everywhere on the internet are the same as I have written.
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class JMSProducer {
public static void main(String[] args) {
try {
// Create a ConnectionFactory
ConnectionFactory connectionFactory=new ActiveMQConnectionFactory("admin", "admin",
ActiveMQConnection.DEFAULT_BROKER_URL);
// Create a Connection
Connection connection = connectionFactory.createConnection();
//Error seen in above line
connection.start();
// Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination
Destination destination = session.createQueue("testQ");
// Create a MessageProducer from the Session to the Queue
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// Create a messages
TextMessage message = session.createTextMessage("Helloworld");
producer.send(message);
session.close();
connection.close();
System.out.println("Message sent");
}
catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
}
Sholud have done ActiveMQConnection connection = connectionFactory.createConnection(); instead of Connection connection = connectionFactory.createConnection();. Now the code is running fine.

Add manually mappedName in Message Driven Bean at runtime

I need to make simple Message Driven Bean that will listen on dynamically added queue locataions. I have tried few ways to implement this, but none of them worked. I have appplication that uses esb and java message queues, and I'm trying to read queue location from config file, during the runtime, and thus tell my message driven bean what is the queue on which to listen. I am not either sure that this is possible.
I also tried to implement message listener, but because I have to use ejb module, and ejb module does not support main method, it requires his own container (like message driven bean), I don't know what to use instead of main method to achive the same goal. I am not able to use session beans because I need to achieve asynchronous communication between client and service.
I also tried to use client application (although it is not one of the options), but maven project does not support debug and run functions for this type of application in netbeans.
Does anyone know any solution for this problem, or at least have some idea?
This may not be the best solution, but it is possible to receive and process JMS messages asynchronously with a Stateful Session Bean doing something like this:
package com.example.statefuljms;
import javax.annotation.Resource;
import javax.ejb.Local;
import javax.ejb.Stateful;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
#Stateful
#Local(MessageReceiverLocal.class)
public class MessageReceiver implements MessageReceiverLocal, MessageListener {
#Resource(mappedName = "ConnectionFactory")
private ConnectionFactory connectionFactory;
private QueueConnection connection;
#Override
public void start(String queueName) throws JMSException, NamingException {
Context initialContext = new InitialContext();
connection = (QueueConnection) connectionFactory.createConnection();
QueueSession session = (QueueSession) connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) initialContext.lookup(queueName);
QueueReceiver receiver = session.createReceiver(queue);
receiver.setMessageListener(this);
connection.start();
}
#Remove
#Override
public void stop() throws JMSException {
connection.stop();
connection.close();
}
#Override
public void onMessage(Message message) {
// handle message here
}
}
Use a Singleton to test:
package com.example.statefuljms;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.jms.JMSException;
import javax.naming.NamingException;
#Startup
#Singleton
public class Test {
#EJB
private MessageReceiverLocal messageReceiver;
#PostConstruct
public void run() {
messageReceiver.start("/queue/myQueue");
}
#PreDestroy
public void cleanup() {
messageReceiver.stop();
}
}

Categories

Resources