7

Ending Conversations

The "Confirm" button is bound to the action method confirm() of HotelBookingAction.

<h:commandButton value="Confirm" action="#{hotelBooking.confirm}" id="confirm"/>

The confirm() method is tagged with the @End annotation, which ends the long-running conversation and results in all state associated with the conversation being destroyed at the end of the request. Since the pages.xml file specifies a redirect for this action, the state will not be destroyed until after the redirect completes. Note that even the success message that we create using the built-in facesMessages component is transparently propagated across the redirect!

@End public void confirm() { if (booking==null || hotel==null) return "main"; em.persist(booking); facesMessages.add("Thank you, #{user.name}, your confimation number " + "for #{hotel.name} is #{booking.id}"); log.info("New booking: #{booking.id} for #{user.username}"); events.raiseEvent("bookingConfirmed"); } @End public void cancel() {} @Destroy @Remove public void destroy() {} }

When the conversation state is finally destroyed, Seam calls the @Destroy method, which results in removal of the SFSB.

Notice that the HotelBookingAction.confirm() method raises a bookingConfirmed event before it finishes. The event mechanism allows Seam components to communicate with each other without direct coupling. In this case, the BookingListAction component captures the bookingConfirmed event and refreshes the existing booking list for the current user.

public class BookingListAction implements BookingList, Serializable { ... ... @Factory @Observer("bookingConfirmed") public void getBookings() { bookings = em.createQuery("from Booking b where b.user.username = " + ":username order by b.checkinDate") .setParameter("username", user.getUsername()) .getResultList(); } }