官术网_书友最值得收藏!

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.

Note that we can define more observer objects, and all of them will be invoked upon firing this event, which is the role of the @Any annotation.

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.

主站蜘蛛池模板: 蕲春县| 永登县| 呈贡县| 大城县| 通州区| 特克斯县| 界首市| 凤凰县| 六枝特区| 巴青县| 无为县| 盈江县| 甘肃省| 张掖市| 连云港市| 育儿| 尚志市| 信宜市| 全南县| 关岭| 游戏| 洛宁县| 黔南| 偃师市| 阿城市| 盐池县| 石柱| 定日县| 莲花县| 怀宁县| 公主岭市| 周口市| 开平市| 辽宁省| 麦盖提县| 博客| 从江县| 榆中县| 舟山市| 屯门区| 申扎县|