1

Good day ALL,

I'm having issues while sending an email notification from an MDB onMessage method after a new user signup.

I'm using a Queue

The problem is that the messageListener keeps resending every message in the queue, and this result in an email address getting different email notification (both the intended and unintended, old and new, etc) whenever a new user signup.

below is the client code;

    public String createAccount(String firstName, String middleName, String lastName, String username,
        String password, String confirmPassword, String email, String confirmEmail, String Organization,
        String address, String state, String country, String gRecaptchaResponse) {

    boolean verified = false;
    try {
        verified = VerifyRecaptcha.verify(gRecaptchaResponse);
    } catch (IOException ex) {
        Logger.getLogger(AdminFacade.class.getName()).log(Level.SEVERE, "Captcha palava_" + ex.getMessage(), ex);
    }

    if (verified) {
        Query q = em.createNamedQuery("Admin.findByUsername");
        q.setParameter("username", username);

        if (q.getResultList().size() > 0) {
            return "Username <" + username + "> already exists. Pls try a different username";
        }

        if (!password.equals(confirmPassword)) {
            return "Password Mis-match";
        }

        if (!email.equals(confirmEmail)) {
            return "E-mail Mis-match";
        }

        try {
            Admin admin = new Admin();

            admin.setEmail(email);
            admin.setFirstName(firstName);
            admin.setMiddleName(middleName);
            admin.setLastName(lastName);
            admin.setOrganization(Organization);
            admin.setEmail(email);
            admin.setAddress(address);
            admin.setState(state);
            admin.setCountry(country);
            admin.setExamSessionId(UniqueValueGenerator.generate());
            admin.setResultDisplay(true);

            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(password.getBytes());
            byte byteData[] = md.digest();

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < byteData.length; i++) {
                sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
            }

            admin.setPassword(sb.toString());

            admin.setUsername(username);

            em.persist(admin);

            //set the password back to the literal password so that email sent will show the literal password
            admin.setPassword(password);

            QueueConnection connection = null;
            Session jmssession = null;
            MessageProducer messageProducer = null;
            try {

                connection = connectionFactory.createQueueConnection();
                jmssession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                messageProducer = jmssession.createProducer(queue);

                ObjectMessage message = jmssession.createObjectMessage();

                message.setObject(admin);
                System.out.println("Sending message attempt: ");
                System.out.println(messageProducer.getDestination().toString());
                System.out.println(messageProducer.getDeliveryMode());
                System.out.println(messageProducer.getPriority());
                messageProducer.send(message);

            } catch (JMSException ex) {
                Logger.getLogger(AdminFacade.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);

                return "Account was successfully created but it looks like we were unable to notify your email. Please check your "
                        + "mail NOW for notification  and if you can't find it, send us a mail at abc@abc.com";
            } finally {
                try {
                    connection.close();
                    jmssession.close();
                    messageProducer.close();
                    System.out.println("All Closed");
                } catch (JMSException ex) {
                    Logger.getLogger(AdminFacade.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
                }
            }

            return "Success";

        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(AdminFacade.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
            return "Something went wrong, please make sure all fields are filled correctly";
        }
    } else {
        return "You missed the Recaptcha, please retry";
    }
}

And here is the MDB code;

package utility;

import entity.Admin;
import entity.Housekeeping;
import java.util.logging.Level;
import java.util.logging.Logger;
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.TextMessage;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.mail.MessagingException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import session.AdminFacade;
import session.HousekeepingFacade;


@MessageDriven(mappedName = "jms/notificationMailer", activationConfig = {
//    @ActivationConfigProperty(propertyName = "destinationLookup",     propertyValue = "jms/notificationMailer")
        @ActivationConfigProperty(propertyName = "acknowledgeMode",     propertyValue = "Auto-acknowledge")
,
        @ActivationConfigProperty(propertyName = "destinationType",     propertyValue = "javax.jms.Queue")
})
public class NotificationMailer implements MessageListener {

@Resource
private MessageDrivenContext mdc;

@EJB
HousekeepingFacade housekeepingFacade;
@PersistenceContext(unitName = "PU")
private EntityManager em;

public NotificationMailer() {
}

@Override
public void onMessage(Message inMessage) {
    TextMessage msg = null;
    ObjectMessage objMsg = null;

    try {
        if (inMessage instanceof TextMessage) {
            msg = (TextMessage) inMessage;
            System.out.println("MESSAGE BEAN: Message received: "
                    + msg.getText());
        }else if (inMessage instanceof ObjectMessage){
            objMsg = (ObjectMessage) inMessage;
            Admin admin = (Admin) objMsg.getObject();

                System.out.println(admin.getEmail());
            Query q2 = em.createNamedQuery("Admin.findByUsername");
            q2.setParameter("username", admin.getUsername());

            Admin u = (Admin) q2.getSingleResult();

            try {
                String recipient = admin.getEmail();
                String subject = "Account Creation Confirmation";
                String content = "my content";

                Housekeeping housekeeping = housekeepingFacade.findAll().get(0);
                EmailUtility.sendEmail(EmailUtility.HOST, EmailUtility.PORT, EmailUtility.USERNAME, housekeeping.getNoReplyPw(), recipient, subject, content, true);
                EmailUtility.sendEmail(EmailUtility.HOST, EmailUtility.PORT, EmailUtility.USERNAME, housekeeping.getNoReplyPw(), "abc@abc.com", "New Admin Sign-up", "A new admin with account name: " + u.getUsername() + " and email " + u.getEmail() + " just signed up", false);
                System.out.println("Done sending");
            } catch (MessagingException ex) {                    
                String errMsg = "Account was successfully created but it looks like we were unable to notify your email. Please check your "
                        + "mail NOW for notification  and if you can't find it, send us a mail at support@abc.com";
                Logger.getLogger(AdminFacade.class.getName()).log(Level.SEVERE, ex.getMessage()+"___"+errMsg, ex);
            }

        }else {
            System.out.println("Message of wrong type: "
                    + inMessage.getClass().getName());
        }
    } catch (JMSException e) {
        e.printStackTrace();
        mdc.setRollbackOnly();
    } catch (Throwable te) {
        te.printStackTrace();
    }

}   

}

  • I notice the issue only happens when I'm calling the EmailUtility.sendEmail() method; when I comment out the call, the onMessage listener method behaves fine except that it doesn't send the notification email. NB: EmaUtility class is fine. It works well in every other instance within my application except when called within MDB – Christian Oliver Jul 16 '17 at 10:02
  • You're not getting any exceptions? And it prints "Done sending" exactly once? What exactly does EmailUtility do, and what does the [JavaMail debug output](https://javaee.github.io/javamail/FAQ#debug) show? – Bill Shannon Jul 17 '17 at 06:30
  • Please see my answer below. Many thanks. – Christian Oliver Jul 17 '17 at 17:10

1 Answers1

0

@BillShannon

Thanks for your kind assistance, I was able to resolve the issue after some hours. I had to open my library and pick up some paperback books on EJB and it was indeed helpful. I noticed the issue with my application was something called "Poisoned Messages".

A Poisoned Message is a message that keeps redelivering because the message consumer refuses to acknowledge the receipt of the message (which IS NOT the case of mine) or the logic adopted in coding the onMessage listener method of the NotificationMailer class is not acceptable to GlassFish JMS MOM (which is the case of mine). Calling a method (such as EmailUtility.sendMail()) which is "likely" to throw a system exception (such as MessageException) will result in a Poisoned Message.

My solution was to:

  1. Rework the logic of sendMail() method in EmailUtility class to deal with the MessageException instead of throwing it.

  2. Rework the logic of onMessage() listener method of the NotificationMailer class to call EmailUtility.sendMail() without involving a try-catch block.