Store the message which is received/sent to the queue using JmsListener - spring-boot

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);
}
}

Related

Cloning javax.mail.Message and Cloning javax.mail.Multipart, Java 8

I'm implementing a mail Sender, near 1'6000.000 mails (with images and PDF) in one day per month (closing month extract), the mails are about 12 products...
I need to fill a Message Scratch per product... in order to not read (per email) else per product.
I'm trying to implement cloning javax.mail.Message and javax.mail.Multipart in order to be faster.
AddContent to Multipart
public static void addContent(final Multipart multipart, String contenidoCorreo) throws Exception {
MimeBodyPart mimeBodyPart = new PreencodedMimeBodyPart("8bit");
mimeBodyPart.setText(contenidoCorreo, "iso-8859-1", "html");
multipart.addBodyPart(mimeBodyPart, 0);
}
Add Image per Bytes
public static void addImageToMultipart(final Multipart multipart, byte[] contenidoImagen, String nombreImagen) throws Exception {
MimeBodyPart imagenMimeBodyPart = new MimeBodyPart();
try {
ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource(contenidoImagen, "image/*");
imagenMimeBodyPart.setDataHandler(new DataHandler(byteArrayDataSource));
imagenMimeBodyPart.setFileName(nombreImagen);
imagenMimeBodyPart.setContentID("<" + nombreImagen + ">");
imagenMimeBodyPart.setDisposition(MimeBodyPart.INLINE);
multipart.addBodyPart(imagenMimeBodyPart);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
AddPDF per File
public static void addPDF(final Multipart multipart, String ruta, String nombre) throws Exception {
Path path = Paths.get(ruta, nombre);
if (path.toFile().exists()) {
MimeBodyPart preencodedMimeBodyPart = new PreencodedMimeBodyPart("base64");
preencodedMimeBodyPart.attachFile(path.toFile());
preencodedMimeBodyPart.setFileName(nombre);
preencodedMimeBodyPart.setHeader("Content-Type", "application/pdf");
preencodedMimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
multipart.addBodyPart(preencodedMimeBodyPart);
MimeBodyPart pdfMimeBodyPart = new MimeBodyPart();
}
My Cloning Message
public static Message cloneMessage(Message source) {
//Multiple and Separated Exceptions because maybe not all properties are defined in some time.
Message target = new MimeMessage(source.getSession());
try {
if (source.getFrom() != null && source.getFrom().length > 0) {
Address address = (source.getFrom()[0]);
target.setFrom(new InternetAddress(((InternetAddress) address).getAddress(), ((InternetAddress) address).getPersonal()));
}
} catch (Exception ex) {
//Handle Exception
}
try {
target.setSentDate((Date) (source.getSentDate().clone()));
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setRecipients(Message.RecipientType.TO, target.getRecipients(Message.RecipientType.TO).clone());
} catch (MessagingException ex) {
//Handle Exception
}
try {
Enumeration numerationHeaders = source.getAllHeaders();
while (numerationHeaders.hasMoreElements()) {
Header header = (Header) numerationHeaders.nextElement();
target.addHeader(header.getName(), header.getValue());
}
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setSubject(new String(source.getSubject()));
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setContent(cloneMultipart((Multipart)(source.getContent())));
} catch (Exception ex) {
//Handle Exception
}
return target;
}
Cloning Multipart
public static Multipart cloneMultipart(Multipart source) {
MimeMultipart target = new MimeMultipart();
try {
for (int i = 0; i < source.getCount(); i++) {
MimeBodyPart mimeBodyPart = (MimeBodyPart)source.getBodyPart(i);
mimeBodyPart //?????
}
} catch (MessagingException ex) {
//Handle Exception
}
return target;
}
How cloning Multipart?
some advice to clone Message?
How detect the Content (the used with addContent method) has been added?

org.zeromq.ZMQException: Errno 48 : Address already in use

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?

Trying to get the message from server but receive call gets blocked

// 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.

in java8 how to a define a function with custom code only?

I want to send two kinds email, and some logic could shared. e.g.
try {
MimeMessage msg = javaMailService.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(msg, true, DEFAULT_ENCODING);
//custom code here ...
} catch (MessagingException e) {
logger.error("build email fail", e);
} catch (Exception e) {
logger.error("send email fail", e);
}
above is common code (e.g. sendEmail(Function customCode)), below is custom code of sending email to foo
logger.info("send count mail to {}", toFoo);
helper.setFrom(sender);
helper.setTo(toFoo);
helper.setSubject("Foo Subject");
String content = generateFooContent(foo); //use fooTemplate.ftl
helper.setText(content, true);
javaMailService.send(msg);
I want to this effect,
Function fooFunc = ()->{logger.info("send count mail to {}", toFoo);
helper.setFrom(sender);
helper.setTo(toFoo);
helper.setSubject("Foo");
String content = generateFooContent(foo);
helper.setText(content, true);
javaMailService.send(msg);}
then call sendEmail method,
sendEmail(fooFunc);
If I want to send bar message,
Function barFunc = ()->{...} //cunstom code here
sendEmail(barFunc);
In java8 could achieve this? if could how?
Your "Function" has a signature:
void doStuff(MimeMessageHelper helper)
We already have one of these - it's called a Consumer<MimeMessageHelper>.
So:
final Consumer<MimeMessageHelper> messageCreator = ...
try {
MimeMessage msg = javaMailService.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(msg, true, DEFAULT_ENCODING);
messageCreator.accept(helper);
javaMailService.send(msg);
} catch (MessagingException e) {
logger.error("build email fail", e);
} catch (Exception e) {
logger.error("send email fail", e);
}
Now, to define your sender simply use:
BiConsumer<MimeMessageHelper> fooFunc = helper -> {
logger.info("send count mail to {}", toFoo);
helper.setFrom(sender);
helper.setTo(toFoo);
helper.setSubject("Foo");
String content = generateFooContent(foo);
helper.setText(content, true);
}
P.S. please note my formatting.
Thanks #Boris the Spider, it do works, see below
private void sendFooHtmlMessage(List<Foo> body) {
BiConsumer<MimeMessage,MimeMessageHelper> fooFunc = (msg,helper) -> {
logger.info("send foo mail to {}", toFoo);
try {
helper.setTo(toFoo);
helper.setSubject("Foo Subject");
String content = generateFooContent(body);
helper.setText(content, true);
javaMailService.send(msg);
} catch (Exception e) {
}
};
sendMessage(fooFunc);
}
private void sendMessage(BiConsumer<MimeMessage,MimeMessageHelper> consumer) {
try {
final MimeMessage msg = javaMailService.createMimeMessage();
final MimeMessageHelper helper = new MimeMessageHelper(msg, true, DEFAULT_ENCODING);
helper.setFrom(sender);
consumer.accept(msg, helper);
} catch (MessagingException e) {
logger.error("build email failed", e);
} catch (Exception e) {
logger.error("send email failed", e);
}
}
but still lack something, see above code I have to catch exception in fooFunc, actually I want to throw it because in common sendMesage will catch these exception.
So I adopt another way, see below
public interface SendMessageAction {
void action(MimeMessage msg, MimeMessageHelper helper) throws MessagingException;
}
private void sendMessage(SendMessageAction action) {
//...
}
private void sendFooHtmlMessage(List<Foo> body) {
SendMessageAction fooAction = (msg, helper) -> {
logger.info("send foo mail to {}", toFoo);
//...
};
sendMessage(fooAction);
}

testing if my jms listener is working

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...

Resources