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?
Below is the Java code to consume the durable subscription
private void execute()throws Exception {
logger.debug("Creating JNDI context");
Properties jndiProps = new Properties();
jndiProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, config.getJndiFactory());
jndiProps.setProperty(Context.PROVIDER_URL, config.getJndiProviderUrl());
jndiProps.setProperty(Context.SECURITY_CREDENTIALS, config.getJndiSecurityCredential());
jndiProps.setProperty(Context.SECURITY_PRINCIPAL, config.getJndiSecurityPrincipal());
logger.debug("JNDI properties: " + jndiProps.toString());
jndiContext = new InitialContext(jndiProps);
logger.debug("JNDI context created successfully");
logger.debug("Looking up ConnectionFactory : " + config.getJmsConnFactory());
TopicConnectionFactory connFactory = (TopicConnectionFactory) jndiContext.lookup(config.getJmsConnFactory());
logger.debug("Creating connection object");
conn = connFactory.createTopicConnection(config.getJmsUserName(), config.getJmsPasswd());
logger.debug("Connection object successfully created");
TopicSession session = null;
MessageConsumer subscriber = null;
try {
session = conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
logger.debug("Starting connection");
conn.start();
logger.debug("Getting destinaton");
Topic topic = (Topic)jndiContext.lookup(config.getDestination());
if (topic == null) {
throw new RuntimeException("Invalid destination");
}
logger.debug("Creating durable subscriber");
if(config.isDurable()){
subscriber = session.createDurableSubscriber(topic, config.getSubscriberId());
}else{
subscriber = session.createSubscriber(topic);
}
boolean runFlag = true;
do {
logger.debug("Receiving messages...");
TextMessage message = (TextMessage) subscriber.receive(DEF_TIMEOUT_MILLIS);
if (message != null) {
logger.debug("Received message : " + message.getText());
continue;
}
logger.debug("No available messages now");
runFlag = false;
} while (runFlag);
logger.debug("There is no more messages available. Exiting...");
} finally {
if(config.isDurable()){
session.unsubscribe(config.getSubscriberId());
}
close(subscriber);
close(session);
}
}
While executing I am getting the "TCPLink Error: invalid magic in the message". And after that, session and connection is getting terminated automatically.
javax.jms.IllegalStateException: Session is closed
javax.jms.JMSException: Connection has been terminated
Please help.
Thanks in advance
Is there any way to get count number of pending messages in jms queue. My aim is to close the connection if there is no message remaining in the queue to process. how can i achieve this.
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection("admin", "admin");
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(subject);
MessageConsumer consumer = session.createConsumer(destination);
while (true) {
Message message = consumer.receive();
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Incoming Message:: '" + textMessage.getText() + "'");
}
}
The only reliable way to get the true Queue count form the broker is to use the JMX MBean for the Queue and call the getQueueSize method.
The other programmatic alternative is to use the Statistics Broker Plugin which requires that you be able to change broker configuration to install it. Once installed you can send a special message to the control queue and get a response with details for the destination you want to monitor.
Using a QueueBrowser doesn't give you a true count because the browser has a max limit on how many messages it will page into memory to send you, so if your queue is deeper than the limit you won't get the actual size, just the value of the max page size limit.
I have done this by using createBrowser method below is my updated code.
public static void main(String[] args) throws JMSException {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection("admin", "admin");
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(subject);
int queueSize = QueueConsumer.getQueueSize(session, (Queue) destination);
System.out.println("QUEUE SIZE: " + queueSize);
MessageConsumer consumer = session.createConsumer(destination);
for (int i = 0; i < queueSize; i++) {
Message message = consumer.receive();
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Incomming Message: '" + textMessage.getText() + "'");
}
}
connection.close();
}
private int getQueueSize(Session session, Queue queue) {
int count = 0;
try {
QueueBrowser browser = session.createBrowser(queue);
Enumeration elems = browser.getEnumeration();
while (elems.hasMoreElements()) {
elems.nextElement();
count++;
}
} catch (JMSException ex) {
ex.printStackTrace();
}
return count;
}
I have done this with jmx it worked thanx #Tim Bish
here is my updated code
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://0.0.0.0:44444/jndi/rmi://0.0.0.0:1099/karaf-root");
HashMap<String, String[]> environment = new HashMap<String, String[]>();
String[] creds = { "admin", "admin" };
environment.put(JMXConnector.CREDENTIALS, creds);
JMXConnector jmxc = JMXConnectorFactory.connect(url, environment);
MBeanServerConnection connection = jmxc.getMBeanServerConnection();
ObjectName nameConsumers = new ObjectName("org.apache.activemq:type=Broker,brokerName=amq,destinationType=Queue,destinationName=myqueue");
DestinationViewMBean mbView = MBeanServerInvocationHandler.newProxyInstance(connection, nameConsumers, DestinationViewMBean.class, true);
long queueSize = mbView.getQueueSize();
System.out.println(queueSize);
Just break the loop and close the connection if your JMS Message is null..
while (true) {
Message message = consumer.receive(2000);
if (message == null){
break;
}
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Incoming Message:: '" + textMessage.getText() + "'");
}
}
connection.close();
// 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.