// This is send message from where I am sending message to server, Its working fine
public void sendMessage(com.google.protobuf.Message sendmessage) {
try {
createJmsTemplate();
createJmsTemplateReciever();
JmsMessageCreator jmsMessageCreator = new JmsMessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
BytesMessage msg = session.createBytesMessage();
msg.writeBytes(sendmessage.toByteArray());
return msg;
}
};
MessageCreator messageCreator = new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
Message msg = jmsMessageCreator.createMessage(session);
msg.setJMSCorrelationID("2708");
return msg;
}
};
jmsTemplate.send(messageCreator);
System.out.println("Message sent... ");
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
//But when i am calling this method, at receive call it gets blocked...
public void recieveMessage() {
try {
byteMessage = (BytesMessage) jmsTemplateReciever.receive();
try {
if (byteMessage != null) {
byte[] byteArr = new byte[(int) byteMessage.getBodyLength()];
for (int i = 0; i < (int) byteMessage.getBodyLength(); i++) {
byteArr[i] = byteMessage.readByte();
String s = new String(byteArr);
System.out.println(s);
}
String s = new String(byteArr);
System.out.println(s);
byteMessage.acknowledge();
}
} catch (JMSException e) {
}
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
}
As described in section 9.2.2 of JMS 1.1 Specification, the receive() call blocks indefinitely until a message arrives on the queue. Hence the call is getting blocked in your application.
One option for you is to specify a wait time, for example receive(3000) which waits for 3 seconds and comes out if no message arrives in 3 seconds. JMS implementer might be providing another form of receive method where the method returns immediately if there are no messages in the queue.
The other option is to use a message listener for receiving messages asynchronously as described JMS 1.1 Specifications section 9.3.1. Your application gets notified by the JMS provider whenever a message arrives in a queue.
Related
Is there any way to put interceptor in jms listener..requirement is to store the request and response while reading and writing to message queue
#JmsListener(destination = "${ibm.mq.queueName}", containerFactory = "containerFactory")
public void readAndProcessMessage(Message<?> message) throws Exception {
UnProcessedEvent unProcessedEvent;
String eventMessage = message.getPayload().toString();
log.info("Received an event: " + eventMessage);
try {
String iban = getIban(eventMessage);
// Identifying Topic
for (Mandate mandate : configProperties.getMandates()) {
for (Topic topic : mandate.getTopic()) {
if (topic.getAccountNumber().equals(iban)) {
publisherService.publishEvent(iban, eventMessage);
return;
}
}
}
unProcessedEvent = UnProcessedEvent.builder().incomingReqPayload((eventMessage)).reason("No Topic Found")
.reasonCode(HttpStatus.BAD_REQUEST.toString()).build();
unprocessedEventRepository.save(unProcessedEvent);
} catch (JAXBException e) {
log.info("Exception while parsing the event message: " + e.getMessage());
unProcessedEvent = UnProcessedEvent.builder().incomingReqPayload((eventMessage)).reason("Bad Request")
.reasonCode(HttpStatus.BAD_REQUEST.toString()).build();
unprocessedEventRepository.save(unProcessedEvent);
}
}
I am trying to implement a pub-sub example using ZeroMQ.
I run the publisher's code in a docker container and the subscriber's code in another one.
My subscriber is:
private ZMQ.Context context;
{
context = ZMQ.context(1);
}
public void receive() {
System.out.println("Getting subscriber, listening to tcp://localhost:5565");
getSubscriber();
byte[] raw;
System.out.println("Watching for new Event messages...");
try {
while (!Thread.currentThread().isInterrupted()) {
raw = subscriber.recv();
System.out.println("Event received " + raw);
}
} catch (Exception e) {
System.out.println("Unable to receive messages via ZMQ: " + e.getMessage());
}
if (subscriber != null)
subscriber.close();
subscriber = null;
System.out.println("Attempting restart of Event message watch.");
receive();
}
private ZMQ.Socket getSubscriber() {
if (subscriber == null) {
try {
subscriber = context.socket(ZMQ.SUB);
subscriber.connect("tcp://localhost:5565");
subscriber.subscribe("".getBytes());
} catch (Exception e) {
System.out.println("Unable to get a ZMQ subscriber. Error: " + e);
subscriber = null;
}
}
return subscriber;
}
And my publisher is:
private ZMQ.Context context;
{
context = ZMQ.context(1);
}
public synchronized void sendEventMessage(Event event) {
try {
if (publisher == null) {
getPublisher();
}
if (publisher != null) {
publisher.send(event);
}
} catch (Exception e) {
System.out.println("Unable to send message via ZMQ");
}
}
private void getPublisher() {
try {
if (publisher == null) {
publisher = context.socket(ZMQ.PUB);
publisher.bind("tcp://192.168.32.9:5565"); //where 192.168.32.9 is the IP of the subscriber's docker container
Thread.sleep(PUB_UP_SLEEP); // allow subscribers to connect
}
} catch (Exception e) {
System.out.println("Unable to get a publisher. Error: " + e);
publisher = null;
}
}
When I start the application, I register a subscriber and the logs are:
[2018-12-10 08:01:02.138] boot - 1 INFO [main] --- ZeroMQEventSubscriber: Getting subscriber, listening to tcp://localhost:5565
[2018-12-10 08:01:02.249] boot - 1 INFO [main] --- ZeroMQEventSubscriber: Watching for new Event messages...
My problem is that when I invoke sendEventMessage, the subscriber does not receive anything and on the publisher I get this error:
[2018-12-10 08:54:16.388] boot - 1 ERROR [task-scheduler-5] --- ZeroMQEventPublisherImpl: Unable to get a publisher. Error: org.zeromq.ZMQException: Errno 48 : Address already in use
Any ideas why I cannot bind to the address where the subscriber has connected?
I am creating a JMS chat application using activemq and spring boot. I am trying to send message from producer to multiple subscribers. I am able to send message i.e message is en-queued. but in my receiver part message is unable to de-queue.` I am using the below code for communicating message from producer to multiple subscribers.
public class WelcomeController implements MessageListener {
public static Boolean TRANSACTIONAL = false;
public static String TOPIC_NAME = "firstTopic";
public static String BROKER_URL = "tcp://localhost:61616";
public static String BROKER_USERNAME = "admin";
public static String BROKER_PASSWORD = "admin";
public void createProducer() throws JMSException {
Connection connection = null;
Session session = null;
try {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
connectionFactory.setBrokerURL(BROKER_URL);
connectionFactory.setPassword(BROKER_USERNAME);
connectionFactory.setUserName(BROKER_PASSWORD);
connection = connectionFactory.createConnection();
connection.setClientID("CircliTopic");
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
for (int i = 1; i <= 3; i++) {
session = connection.createSession(TRANSACTIONAL,
Session.AUTO_ACKNOWLEDGE);
Topic destination = session.createTopic(TOPIC_NAME);
MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage();
message.setText( "My text message was send and received");//
System.out.println("Sending text '" + message + "'");
producer.send(message);
MessageConsumer consumer = session
.createDurableSubscriber(destination, "Listener" + i);
consumer.setMessageListener(new WelcomeController());
}
} finally {
connection.close();
}`
}
#Override
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage text = (TextMessage) message;
System.out.println(" - Consuming text msg: " + text.getText());
} else if (message instanceof ObjectMessage) {
ObjectMessage objmsg = (ObjectMessage) message;
Object obj = objmsg.getObject();
System.out.println(" - Consuming object msg: " + obj);
} else {
System.out.println(
" - Unrecognized Message type " + message.getClass());
}
} catch (JMSException e) {
e.printStackTrace();
}
}
I am able to get consuming text message in my console but my message is not de-queued to the subscribers and also in my activemq server message is not dequeued.
You are creating a Topic subscription only after the message has been sent and that won't work because these are Topics and a Topic with no subscriptions simply discards all messages sent to it. You need to establish a durable Topic subscription prior to any messages being sent, or switch to Queues if your design allows as a Queue will store a message sent to it until consumed.
It is hard to say more without knowing your requirements but it seems you need to spend a little bit more time understanding how Topics work.
I was fixing sonar lint error in my project. I have seen a block of Code where sonar lint is giving me error of rule squid:S2276 to replace Thread.sleep(100); with wait(). But wait() should be in conditional loop to escape spurious wakeup problem. But I am not getting such a condition how I should use.
Can i achieve the same thing without sleep()
public class ACTOOBEventSubSMSProducer {
private ACTOOBEventSubSMSProducer(){
super();
}
private static Logger logger = LoggerManager.getInstance().getCoreProcessingLogger();
public static final String CONNECTION_FACTORY = "java:jboss/activemq/ConnectionFactory";
static final String QUEUE_NAME = "java:jboss/exported/jms/queue/actOOBEventSubscriptionSMS";
static ConnectionFactory connectionFactory = null;
static Connection connection = null;
static Session session = null;
static Destination destination = null;
static MessageProducer messageProducer = null;
static {
connectionFactory = ServiceLocator.getJmsConnectionFactory(CONNECTION_FACTORY);
try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
destination = ServiceLocator.getJmsDestination(QUEUE_NAME);
messageProducer = session.createProducer(destination);
messageProducer.setDisableMessageID(true);
messageProducer.setDisableMessageTimestamp(true);
} catch (JMSException e) {
logger.error("Error in creating ConnectionFactory",e);
}
}
/**
* This method sends OOB Event SMS Message in Queue.
*
* #param message
*/
public static synchronized void sendMessage(Serializable payload) throws JmsProducerException {
try {
ObjectMessage message = session.createObjectMessage(payload);
messageProducer.send(message, javax.jms.DeliveryMode.NON_PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY,
1800000);
} catch (JMSException je) {
try {
Thread.sleep(100);
ObjectMessage message = session.createObjectMessage(payload);
messageProducer.send(message, javax.jms.DeliveryMode.PERSISTENT, javax.jms.Message.DEFAULT_PRIORITY,
1800000);
} catch (JMSException jee) {
logger.error("Error in sendMessage()",jee);
throw new JmsProducerException(jee);
} catch (InterruptedException ie) {
logger.error("Error in sendMessage()",ie);
Thread.currentThread().interrupt();
throw new JmsProducerException(ie);
}
} catch (ServiceLocatorException sle) {
logger.error("Error in sendMessage()",sle);
throw new JmsProducerException(sle);
}
}
}
A carefully crafted for loop with the iterations count being the number of times you wanted to retry and some exception handling logic to break the loop if things work would do the trick in at a slightly clearer manner perhaps, otherwise using a ScheduledThreadPoolExecutor or or Timer would be an option.
i want to test if my jms listener is working perfectly
when sending 5 messages ( for example ) i added a timer
"Threat.sleep(5000)" and after 5 seconds i want to compare the old messageID with the new messageID that means i want to know if the messages are listened or not so if the ID changes that means that they are successfuly listened
here is my OnMessage code ... but it doesnt work for me :((
public class Consumer implements MessageListener{
public Consumer() {
}
//#Override
public void onMessage(Message message) {
try {
TextMessage tm = (TextMessage) message;
int i;
TextMessage tm2 =tm;
for(i=0;i<1;i++)
{
try {
Thread.sleep(5000);
if (!tm.getJMSMessageID().equals(tm2.getJMSMessageID()))
{
System.out.println("\t----Listener not working----");
}
else {
System.out.println("Message reçu:");
System.out.println("\tTemps: " + System.currentTimeMillis() + " ms");
System.out.println("\tMessage ID: " + tm.getJMSMessageID());
System.out.println("\tCorrel. ID: " + tm.getJMSCorrelationID());
System.out.println("\tConsumed message: " + tm.getText());
System.out.println("\t----Listener working----");
}
//fin else
}
catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
catch (JMSException jex) {
System.out.println("Exception: " + jex);
}
}
}
So you're checking the JMS message id to ensure that no two messages have identical id's? This is probably overkill since, if your listener is receiving messages, it's working!...Nevertheless, your approach has a few problems....
TextMessage tm = (TextMessage) message;
...
TextMessage tm2 =tm;
Thread.sleep(5000);
if (!tm.getJMSMessageID().equals(tm2.getJMSMessageID()))
The above if() will always be false because you're comparing the same message; also, the sleep() statement is useless.
If you want to compare message id's to ensure they are always unique, although if the broker fails to deliver a message the same message will be redelivered and the id would be the same, but anyway, you can use this an an alternative to your code..
private static ConcurrentHashMap<String,String> mesgIdMap =
new ConcurrentHashMap<String, String>();
public Consumer() {
}
//#Override
public void onMessage(Message message) {
try {
TextMessage tm = (TextMessage) message;
if( mesgIdMap.contains( tm.getJMSMessageID()))
System.out.println("\tProcessing JMS message with same ID again!");
//add the message id to the map
mesgIdMap.put( tm.getJMSMessageID(),tm.getJMSMessageID());
//print statements here...