5

Conversations

The hotel booking "wizard" is implemented by a conversation-scoped stateful session bean. The HotelBookingAction maintains state associated with the booking process in the Seam conversation scope. This ensures that if the user is working in multiple brower tabs or multiple brower windows, the various conversations are completely isolated from each other.

To see this working in practice, right click on the "View Hotel" button in the search screen and select "open in new tab" or "open in new window", and try working on multiple hotel bookings simultaneously.

@Stateful @Name("hotelBooking") @Conversational(ifNotBegunOutcome="main") @LoggedIn public class HotelBookingAction implements HotelBooking { @PersistenceContext(type=EXTENDED) private EntityManager em; @In(required=false) @Out private Hotel hotel; @In(required=false) @Out(required=false) @Valid private Booking booking; @In private User user; @In(create=true) private transient FacesMessages facesMessages; @In(required=false) private BookingList bookingList; @RequestParameter private Long hotelId; @Begin public String selectHotel() { if (hotelId!=null) { hotel = em.find(Hotel.class, hotelId); return "hotel"; } else { return null; } } public String bookHotel() { booking = new Booking(hotel, user); Calendar calendar = Calendar.getInstance(); booking.setCheckinDate( calendar.getTime() ); calendar.add(Calendar.DAY_OF_MONTH, 1); booking.setCheckoutDate( calendar.getTime() ); return "book"; } @IfInvalid(outcome=REDISPLAY) public String setBookingDetails() { if (booking==null || hotel==null) return "main"; if ( !booking.getCheckinDate().before( booking.getCheckoutDate() ) ) { facesMessages.add("Check out date must be later than check in date"); return null; } else { return "confirm"; } } @End public String confirm() { if (booking==null || hotel==null) return "main"; em.persist(booking); if (bookingList!=null) bookingList.refresh(); facesMessages.add("Thank you, #{user.name}, your confimation number for #{hotel.name} is #{booking.id}"); //hotels=null; return "confirmed"; } @End public String cancel() { return "main"; } @Destroy @Remove public void destroy() {} }

The conversation begins when selectHotel() is called, and ends when confirm() or cancel() is called.