Nowadays, the companies needs provide response faster and faster to the market, and its success depend of that. This necessity reflects directly on software, that need provide a faster response too. With this, software need be delivered faster and faster, need be scalable more and more and need decrease risks of impacts with updates. Thinking in that, the Java EE have been provided some tools that permit us use Reactive Programming and asynchronous processing, to permit us a faster response to end user and increase and scale the capacity of response to request.
In this post i will show how can we use Event CDI to process tasks using Reactive Programming. In our example i’ll demonstrate how to use Event CDI with synchronous and asynchronous way.
In our scenario, we’ll have a service that receive a request to send an e-mail, and then the service throw an event to an observer that will send an e-mail using JavaMail.
Tools used:
- GlassFish 5.0
- Java EE 8
- IntelliJ IDEA 2017.3.4 (Ultimate Edition)
- mailtrap.io (To use email test)
- Postman (To test the service)
Creating the Qualifiers
First of all, we’ll create a qualifier to distinguish our events. To event of send an e-mail, i will create the qualifier called EmailSender. Below we have the qualifier.
@Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER, ElementType.FIELD}) public @interface EmailSender { }
Creating the Event
In this step we’ll create the event to send an e-mail. This event will have an attribute to email of destination and an attribute to message. Below we have the event example called EmailEvent.
public class EmailEvent { private String emailTo; private String message; public String getEmailTo() { return emailTo; } public void setEmailTo(String emailTo) { this.emailTo = emailTo; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public static EmailEvent build(String emailTo, String message ){ EmailEvent emailEvent = new EmailEvent(); emailEvent.setEmailTo(emailTo); emailEvent.setMessage(message); return emailEvent; } }
Creating the Observer
In this step, we’ll create the observer, that will have two methods. One method to send e-mail with synchronous way and another method to send e-mail with asynchronous way. Below we have the observer example.
public class EmailSender { @Resource(lookup = "mail/MyMailSession") private Session session; private Logger logger = LogManager.getLogger(this.getClass()); //Method used to send email with synchronous way public void send(@Observes @net.rhuanrocha.eventcdiexample.qualifier.EmailSender EmailEvent emailEvent) throws NamingException { runSend(emailEvent); logger.info("Email sent!"); } // Method used to send email with asynchronous way public void sendAsyn(@ObservesAsync @net.rhuanrocha.eventcdiexample.qualifier.EmailSender EmailEvent emailEvent) throws NamingException { runSend(emailEvent); logger.info("Email sent Async!"); } private void runSend(EmailEvent emailEvent) throws NamingException { try { MimeMessage message = new MimeMessage(session); message.setFrom(session.getProperty("mail.address")); message.setRecipients(Message.RecipientType.TO, emailEvent.getEmailTo()); message.setSubject("Sending email with JavaMail"); message.setText(emailEvent.getMessage()); /**Method to send the created message*/ Transport.send(message, session.getProperty("mail.smtp.user"), session.getProperty("mail.smtp.pass")); } catch (MessagingException e) { throw new RuntimeException(e); } } }
Note that on runSend(EmailEvent emailEvent) method, we send an e-mail using the JavaMail spec, and the JavaMail Session is got from context using lookup. With this, you need make a configuration to JavaMail Session with the JNDI name “mail/MyMailSession” on the Server Application. Thus, to this example work well you need configure the following properties on the JavaMail Session:
- mail.address = ${email_from}
- mail.smtp.host=${smtp}
- mail.smtp.port=${port}
- mail.smtp.pass=${passowrd}
- mail.smtp.user=${user}
- mail.smtp.auth=${auth}
Writing the Resource
In this step we’ll create the JAX-RS resource, that will receive a request to send an e-mail and will throw the event to observer. This resource have two methods, one to send email with synchronous way and another to send email with asynchronous way. Below we have the resource called EmailResource.
@Path("email") public class EmailResource { @Inject @EmailSender private Event emailEvent; private Logger logger = LogManager.getLogger(this.getClass()); @POST @Produces(MediaType.APPLICATION_JSON) public Response sendEmail(@Email @NotBlank @FormParam("email") String email, @NotBlank @FormParam("message") String message ){ logger.info("email:"+email + " message:"+message); emailEvent.fire(EmailEvent.build(email,message)); return Response.ok().build(); } @POST @Produces(MediaType.APPLICATION_JSON) @Path("/async") public Response sendEmailAsync(@Email @NotBlank @FormParam("email") String email, @NotBlank @FormParam("message") String message ){ logger.info("email:"+email + " message:"+message); emailEvent.fireAsync(EmailEvent.build(email,message)); return Response.ok().build(); } }
Outputs
To test these codes, i used the Postman and the following results was got.
With synchronous way:
With asynchronous way:
Note that using synchronous way we had a response with 2320 ms and using asynchronous way we had a response with 79 ms. With this, the asynchronous way replied very faster than synchronous way.
Conclusion
The use of Event in CDI permit us using the Reactive Programming in our application. With this, we can promote a decouple between logics and components turning the maintenance better. Furthermore, using Event in CDI we can promote a faster response to end user, because we can working with a non-blocking process.
If you want the completed codes of this example you can access the github and get the code.
https://github.com/rhuan080/jakartaee-event-cdi-example
Leave a Reply