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.