- Developing Middleware in Java EE 8
- Abdalla Mahmoud
- 876字
- 2021-07-23 19:24:35
Using events
Events, as you may know, are runtime incidents that you do care about. CDI provides a loosely coupled model, following the observer design pattern, which allows you to fire an event from a CDI bean, and handling the event from one or more other CDI beans. The key advantages of the CDI events model are:
- Event producers and observers are decoupled from each other
- Observers can define selectors to limit the set of events they consume
- Observers are aware of database transactions and can consume events according to transaction states
In our booking application, we are going to use events in order to notify end users by email with either the success or failure of their booking operations, without tightly coupling the mailing code with the business logic of the booking itself.
Let's start by defining our booking database model; in the next chapter, this will be persisted in a relational database:
public class Booking { private long id; private long cinemaId; private long slotId; private long filmId; private List<Long> seatIds; private BigDecimal amountPaid; public Booking() { } public Booking(long id, long cinemaId, long slotId, long filmId, List<Long> seatIds, BigDecimal amountPaid) { this.id = id; this.cinemaId = cinemaId; this.slotId = slotId; this.filmId = filmId; this.seatIds = seatIds; this.amountPaid = amountPaid; } // getter and setter methods }
Next, we will implement a booking notifier bean, which will represent the observer object for the booking event. The role of this object is to receive a signal when a booking operation has been made, then it prepares and sends an email to the end user confirming with them the booking details. The real code of sending email will be shown in Chapter 9, Sending Mails with JavaMail 1.6. For now, we will log a message to the application server console. Create a class with the name BookingNotifier and write the following code:
@Dependent public class BookingNotifier { public void onBooking(@Observes Booking booking) { System.out.println("New Booking with id " + booking.getId()); // a notification mail should be sent to the user } }
As you have just noticed, the observer is no more than a normal CDI bean. What is special to events here is that we used the @Observers annotation on a parameter of a plain Java method; this tells the container that this method is interested in receiving the events regarding booking objects.
Now, when will this event be fired? Another CDI bean, whose role will be to actually perform the booking operation, will ask to notify all interested objects, as in the following code:
@Dependent public class BookingHandler { private @Inject @Any Event<Booking> bookingEvent; public void book(Booking booking) { // do booking
bookingEvent.fire(booking); } }
As you see, when the booking operation is performed, it will notify our observer about the booking incident, where it will take the appropriate action.
Now, let's complete our example by writing a servlet that simulates a user booking operation:
@WebServlet(urlPatterns = "/cdi-example") public class ExampleServlet extends HttpServlet { @Inject private BookingHandler bookingHandler; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Booking booking = new Booking(1234, 1, 122, 241, (List<Long>) Arrays.asList(1L, 2L, 3L), new BigDecimal("123")); bookingHandler.book(booking); } }
By running the previous example, the output will be as follows:
New Booking with id 1234
Qualifying Events
Events can also be qualified, so we can propagate our event to a bean that is interested in a specific aspect of the event. Let's extend our example to design two types of events related to the booking operation, one for success, and the other for failure. There will be a bean that will react to the success event, where another one will react to the failure. We will define two qualifiers as follows:
@Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Success {} @Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Failure { }
Then, we will replace @Any with the @Success annotation for the onBooking method, and write another one for @Failure as follows:
@Dependent public class BookingNotifier { public void onBooking(@Observes @Success Booking booking) { System.out.println("New Booking with id " + booking.getId()); // a notification mail should be sent to the user } public void onBookingFailed(@Observes @Failure Booking booking) { System.out.println("New Booking failed with id " + booking.getId()); // a notification mail should be sent to the user } }
Now, we will inject two different event propagators in BookingHandler, one for the success, and the other for the failure, as follows:
@Dependent public class BookingHandler { private @Inject @Success Event<Booking> bookingSuccessEvent; private @Inject @Failure Event<Booking> bookingFailedEvent; public void book(Booking booking) { try { // do booking bookingSuccessEvent.fire(booking); } catch (Exception e) { // booking failed bookingFailedEvent.fire(booking); } } }
In the previous code, if the booking has been performed successfully, the success event will be fired, and the onBooking observer will be invoked. If some runtime errors occurred during the booking operation, the failure event will be fired, and the onBookingFailed observer will be invoked. This technique is very useful when we need to track different aspects of the same events in our enterprise application.
- Game Programming Using Qt Beginner's Guide
- C# 2012程序設(shè)計實踐教程 (清華電腦學(xué)堂)
- Android開發(fā)精要
- Leap Motion Development Essentials
- Apache Hive Essentials
- Scratch 3游戲與人工智能編程完全自學(xué)教程
- 大數(shù)據(jù)分析與應(yīng)用實戰(zhàn):統(tǒng)計機器學(xué)習(xí)之?dāng)?shù)據(jù)導(dǎo)向編程
- C語言從入門到精通
- C語言程序設(shè)計
- 軟件項目管理實用教程
- 深度實踐KVM:核心技術(shù)、管理運維、性能優(yōu)化與項目實施
- 高性能PHP 7
- Java RESTful Web Service實戰(zhàn)
- Qt 5.12實戰(zhàn)
- Web開發(fā)新體驗