factored out the hotel search into independent bundle

This commit is contained in:
Scott Andrews
2008-06-30 21:18:27 +00:00
parent 390b914d4f
commit 4ef2afcd91
41 changed files with 1539 additions and 26 deletions

View File

@@ -0,0 +1,206 @@
package org.springframework.samples.springtravel.hotel.booking;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
import org.springframework.samples.springtravel.hotel.search.Hotel;
/**
* A Hotel Booking made by a User.
*/
@Entity
public class HotelBooking implements Serializable {
private Long id;
private User user;
private Hotel hotel;
private Date checkinDate;
private Date checkoutDate;
private String creditCard;
private String creditCardName;
private int creditCardExpiryMonth;
private int creditCardExpiryYear;
private boolean smoking;
private int beds;
public HotelBooking() {
Calendar calendar = Calendar.getInstance();
setCheckinDate(calendar.getTime());
calendar.add(Calendar.DAY_OF_MONTH, 1);
setCheckoutDate(calendar.getTime());
}
public HotelBooking(Hotel hotel, User user) {
this();
this.hotel = hotel;
this.user = user;
}
@Transient
public BigDecimal getTotal() {
return hotel.getPrice().multiply(new BigDecimal(getNights()));
}
@Transient
public int getNights() {
if (checkinDate == null || checkoutDate == null) {
return 0;
} else {
return (int) (checkoutDate.getTime() - checkinDate.getTime())
/ 1000 / 60 / 60 / 24;
}
}
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Basic
@Temporal(TemporalType.DATE)
public Date getCheckinDate() {
return checkinDate;
}
public void setCheckinDate(Date datetime) {
this.checkinDate = datetime;
}
@ManyToOne
public Hotel getHotel() {
return hotel;
}
public void setHotel(Hotel hotel) {
this.hotel = hotel;
}
@ManyToOne
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Basic
@Temporal(TemporalType.DATE)
public Date getCheckoutDate() {
return checkoutDate;
}
public void setCheckoutDate(Date checkoutDate) {
this.checkoutDate = checkoutDate;
}
public String getCreditCard() {
return creditCard;
}
public void setCreditCard(String creditCard) {
this.creditCard = creditCard;
}
@Transient
public String getDescription() {
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
return hotel == null ? null : hotel.getName() + ", "
+ df.format(getCheckinDate()) + " to "
+ df.format(getCheckoutDate());
}
public boolean isSmoking() {
return smoking;
}
public void setSmoking(boolean smoking) {
this.smoking = smoking;
}
public int getBeds() {
return beds;
}
public void setBeds(int beds) {
this.beds = beds;
}
public String getCreditCardName() {
return creditCardName;
}
public void setCreditCardName(String creditCardName) {
this.creditCardName = creditCardName;
}
public int getCreditCardExpiryMonth() {
return creditCardExpiryMonth;
}
public void setCreditCardExpiryMonth(int creditCardExpiryMonth) {
this.creditCardExpiryMonth = creditCardExpiryMonth;
}
public int getCreditCardExpiryYear() {
return creditCardExpiryYear;
}
public void setCreditCardExpiryYear(int creditCardExpiryYear) {
this.creditCardExpiryYear = creditCardExpiryYear;
}
public void validateEnterBookingDetails(MessageContext context) {
if (checkinDate.before(today())) {
context.addMessage(new MessageBuilder().error().source(
"checkinDate").code("booking.checkinDate.beforeToday")
.build());
} else if (checkoutDate.before(checkinDate)) {
context.addMessage(new MessageBuilder().error().source(
"checkoutDate").code(
"booking.checkoutDate.beforeCheckinDate").build());
}
}
private Date today() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, -1);
return calendar.getTime();
}
@Override
public String toString() {
return "Booking(" + user + "," + hotel + ")";
}
}

View File

@@ -0,0 +1,41 @@
package org.springframework.samples.springtravel.hotel.booking;
import java.util.List;
import org.springframework.samples.springtravel.hotel.search.Hotel;
/**
* A service interface for retrieving bookings from a backing
* repository. Also supports the ability to cancel a booking.
*/
public interface HotelBookingAgent {
/**
* Find bookings made by the given user
*
* @param username
* the user's name
* @return their bookings
*/
public List<HotelBooking> findBookings(String username);
/**
* Create a new, transient hotel booking instance for the given user.
*
* @param hotel
* the hotel
* @param userName
* the user name
* @return the new transient booking instance
*/
public HotelBooking createBooking(Hotel hotel, String userName);
/**
* Cancel an existing booking.
*
* @param id
* the booking id
*/
public void cancelBooking(Long id);
}

View File

@@ -0,0 +1,83 @@
package org.springframework.samples.springtravel.hotel.booking;
import java.util.ArrayList;
import java.util.List;
import javax.faces.model.SelectItem;
import org.springframework.stereotype.Service;
@Service
public class ReferenceData {
private List<SelectItem> bedOptions;
private List<SelectItem> smokingOptions;
private List<SelectItem> creditCardExpMonths;
private List<SelectItem> creditCardExpYears;
private List<SelectItem> pageSizeOptions;
public List<SelectItem> getBedOptions() {
if (bedOptions == null) {
bedOptions = new ArrayList<SelectItem>();
bedOptions.add(new SelectItem(new Integer(1), "One king-size bed"));
bedOptions.add(new SelectItem(new Integer(2), "Two double beds"));
bedOptions.add(new SelectItem(new Integer(3), "Three beds"));
}
return bedOptions;
}
public List<SelectItem> getSmokingOptions() {
if (smokingOptions == null) {
smokingOptions = new ArrayList<SelectItem>();
smokingOptions.add(new SelectItem(Boolean.TRUE, "Smoking"));
smokingOptions.add(new SelectItem(Boolean.FALSE, "Non-Smoking"));
}
return smokingOptions;
}
public List<SelectItem> getCreditCardExpMonths() {
if (creditCardExpMonths == null) {
creditCardExpMonths = new ArrayList<SelectItem>();
creditCardExpMonths.add(new SelectItem(new Integer(1), "Jan"));
creditCardExpMonths.add(new SelectItem(new Integer(2), "Feb"));
creditCardExpMonths.add(new SelectItem(new Integer(3), "Mar"));
creditCardExpMonths.add(new SelectItem(new Integer(4), "Apr"));
creditCardExpMonths.add(new SelectItem(new Integer(5), "May"));
creditCardExpMonths.add(new SelectItem(new Integer(6), "Jun"));
creditCardExpMonths.add(new SelectItem(new Integer(7), "Jul"));
creditCardExpMonths.add(new SelectItem(new Integer(8), "Aug"));
creditCardExpMonths.add(new SelectItem(new Integer(9), "Sep"));
creditCardExpMonths.add(new SelectItem(new Integer(10), "Oct"));
creditCardExpMonths.add(new SelectItem(new Integer(11), "Nov"));
creditCardExpMonths.add(new SelectItem(new Integer(12), "Dec"));
}
return creditCardExpMonths;
}
public List<SelectItem> getCreditCardExpYears() {
if (creditCardExpYears == null) {
creditCardExpYears = new ArrayList<SelectItem>();
creditCardExpYears.add(new SelectItem(new Integer(2008), "2008"));
creditCardExpYears.add(new SelectItem(new Integer(2009), "2009"));
creditCardExpYears.add(new SelectItem(new Integer(2010), "2010"));
creditCardExpYears.add(new SelectItem(new Integer(2010), "2011"));
creditCardExpYears.add(new SelectItem(new Integer(2010), "2012"));
}
return creditCardExpYears;
}
public List<SelectItem> getPageSizeOptions() {
if (pageSizeOptions == null) {
pageSizeOptions = new ArrayList<SelectItem>();
pageSizeOptions.add(new SelectItem(new Integer(5), "5"));
pageSizeOptions.add(new SelectItem(new Integer(10), "10"));
pageSizeOptions.add(new SelectItem(new Integer(20), "20"));
}
return pageSizeOptions;
}
}

View File

@@ -0,0 +1,62 @@
package org.springframework.samples.springtravel.hotel.booking;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* A user who can book hotels.
*/
@Entity
@Table(name = "Customer")
public class User implements Serializable {
private static final long serialVersionUID = -3652559447682574722L;
private String username;
private String password;
private String name;
public User() {
}
public User(String username, String password, String name) {
this.username = username;
this.password = password;
this.name = name;
}
@Id
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User(" + username + ")";
}
}

View File

@@ -0,0 +1,69 @@
package org.springframework.samples.springtravel.hotel.booking.impl;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.samples.springtravel.hotel.booking.HotelBooking;
import org.springframework.samples.springtravel.hotel.booking.HotelBookingAgent;
import org.springframework.samples.springtravel.hotel.booking.User;
import org.springframework.samples.springtravel.hotel.search.Hotel;
import org.springframework.samples.springtravel.hotel.search.SearchCriteria;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
/**
* A JPA-based implementation of the Hotel Booking Agent. Delegates to a JPA entity
* manager to issue data access calls against the backing repository. The
* EntityManager reference is provided by the managing container (Spring)
* automatically.
*/
@Repository
public class JpaHotelBookingAgent implements HotelBookingAgent {
private EntityManager em;
@PersistenceContext
public void setEntityManager(EntityManager em) {
this.em = em;
}
@Transactional(readOnly = true)
@SuppressWarnings("unchecked")
public List<HotelBooking> findBookings(String username) {
if (username != null) {
return em
.createQuery(
"select b from HotelBooking b where b.user.username = :username order by b.checkinDate")
.setParameter("username", username).getResultList();
} else {
return null;
}
}
@Transactional(readOnly = true)
public HotelBooking createBooking(Hotel hotel, String username) {
User user = findUser(username);
return new HotelBooking(hotel, user);
}
@Transactional
public void cancelBooking(Long id) {
HotelBooking booking = em.find(HotelBooking.class, id);
if (booking != null) {
em.remove(booking);
}
}
// helpers
private User findUser(String username) {
return (User) em.createQuery(
"select u from User u where u.username = :username")
.setParameter("username", username).getSingleResult();
}
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="bookingDatabase">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.springframework.samples.springtravel.hotel.booking.User</class>
<class>org.springframework.samples.springtravel.hotel.booking.HotelBooking</class>
<class>org.springframework.samples.springtravel.hotel.search.Hotel</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/>
</properties>
</persistence-unit>
</persistence>

View File

@@ -0,0 +1,27 @@
insert into Customer (username, name) values ('keith', 'Keith')
insert into Customer (username, name) values ('erwin', 'Erwin')
insert into Customer (username, name) values ('jeremy', 'Jeremy')
insert into Customer (username, name) values ('scott', 'Scott')
insert into Hotel (id, price, name, address, city, state, zip, country) values (1, 199, 'Westin Diplomat', '3555 S. Ocean Drive', 'Hollywood', 'FL', '33019', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (2, 60, 'Jameson Inn', '890 Palm Bay Rd NE', 'Palm Bay', 'FL', '32905', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (3, 199, 'Chilworth Manor', 'The Cottage, Southampton Business Park', 'Southampton', 'Hants', 'SO16 7JF', 'UK')
insert into Hotel (id, price, name, address, city, state, zip, country) values (4, 120, 'Marriott Courtyard', 'Tower Place, Buckhead', 'Atlanta', 'GA', '30305', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (5, 180, 'Doubletree', 'Tower Place, Buckhead', 'Atlanta', 'GA', '30305', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (6, 450, 'W Hotel', 'Union Square, Manhattan', 'NY', 'NY', '10011', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (7, 450, 'W Hotel', 'Lexington Ave, Manhattan', 'NY', 'NY', '10011', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (8, 250, 'Hotel Rouge', '1315 16th Street NW', 'Washington', 'DC', '20036', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (9, 300, '70 Park Avenue Hotel', '70 Park Avenue', 'NY', 'NY', '10011', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (10, 300, 'Conrad Miami', '1395 Brickell Ave', 'Miami', 'FL', '33131', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (11, 80, 'Sea Horse Inn', '2106 N Clairemont Ave', 'Eau Claire', 'WI', '54703', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (12, 90, 'Super 8 Eau Claire Campus Area', '1151 W Macarthur Ave', 'Eau Claire', 'WI', '54701', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (13, 160, 'Marriot Downtown', '55 Fourth Street', 'San Francisco', 'CA', '94103', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (14, 200, 'Hilton Diagonal Mar', 'Passeig del Taulat 262-264', 'Barcelona', 'Catalunya', '08019', 'Spain')
insert into Hotel (id, price, name, address, city, state, zip, country) values (15, 210, 'Hilton Tel Aviv', 'Independence Park', 'Tel Aviv', '', '63405', 'Israel')
insert into Hotel (id, price, name, address, city, state, zip, country) values (16, 240, 'InterContinental Tokyo Bay', 'Takeshiba Pier', 'Tokyo', '', '105', 'Japan')
insert into Hotel (id, price, name, address, city, state, zip, country) values (17, 130, 'Hotel Beaulac', ' Esplanade L<>opold-Robert 2', 'Neuchatel', '', '2000', 'Switzerland')
insert into Hotel (id, price, name, address, city, state, zip, country) values (18, 140, 'Conrad Treasury Place', 'William & George Streets', 'Brisbane', 'QLD', '4001', 'Australia')
insert into Hotel (id, price, name, address, city, state, zip, country) values (19, 230, 'Ritz Carlton', '1228 Sherbrooke St', 'West Montreal', 'Quebec', 'H3G1H6', 'Canada')
insert into Hotel (id, price, name, address, city, state, zip, country) values (20, 460, 'Ritz Carlton', 'Peachtree Rd, Buckhead', 'Atlanta', 'GA', '30326', 'USA')
insert into Hotel (id, price, name, address, city, state, zip, country) values (21, 220, 'Swissotel', '68 Market Street', 'Sydney', 'NSW', '2000', 'Australia')
insert into Hotel (id, price, name, address, city, state, zip, country) values (22, 250, 'Meli<EFBFBD> White House', 'Albany Street', 'Regents Park London', '', 'NW13UP', 'Great Britain')
insert into Hotel (id, price, name, address, city, state, zip, country) values (23, 210, 'Hotel Allegro', '171 West Randolph Street', 'Chicago', 'IL', '60601', 'USA')

View File

@@ -3,21 +3,21 @@ Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.springframework.samples.springtravel.webapp
Bundle-Name: Spring Travel Web Application Module
Import-Package:
org.springframework.samples.springtravel.hotel,
org.springframework.samples.springtravel.hotel.booking,
org.springframework.samples.springtravel.hotel.search
org.springframework.samples.springtravel.hotel.search,
javax.sql
Import-Bundle:
org.springframework.webflow;version="[2.0.3,3.0.0)",
org.springframework.js;version="[2.0.3,3.0)",
org.springframework.faces;version="[2.0.3,3.0)",
com.springsource.org.apache.myfaces;version="[1.2.0,2.0.0)",
com.springsource.org.apache.myfaces.javax.faces;version="[1.2.0,2.0.0)",
org.springframework.binding;version="[2.0.3,3.0)",
com.springsource.com.sun.facelets;version="[1.1.14,1.2.0)",
org.springframework.security;version="[2.0.0,2.1.0)",
com.springsource.org.jboss.el;version="[2.0.0,3.0.0)"
com.springsource.org.jboss.el;version="[2.0.0,3.0.0)",
com.springsource.org.hsqldb;version="[1.8.0, 2.0.0)"
Import-Library:
org.springframework.spring;version="[2.5.4,3.0.0)",
org.hibernate.ejb;version="[3.3.1.ga, 3.3.1.ga]"
org.hibernate.ejb;version="[3.3.1.ga, 3.3.1.ga]",
org.apache.myfaces;version="[1.2.0,2.0.0)"
Platform-ModuleType: Web
Web-ContextPath: springtravel-faces
Web-DispatcherServletUrlPatterns: /spring/*

View File

@@ -1,23 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xmlns:faces="http://www.springframework.org/schema/faces"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
http://www.springframework.org/schema/faces
http://www.springframework.org/schema/faces/spring-faces-2.0.xsd">
<!-- Maps request URIs to controllers -->
<bean id="hotelHandlerMappings" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/hotel/search=flowController
@@ -42,8 +36,8 @@
<!-- The registry of executable flow definitions in this module -->
<webflow:flow-registry id="flowRegistry" flow-builder-services="facesFlowBuilderServices">
<webflow:flow-location path="classpath:org/springframework/samples/springtravel/hotel/search/search.xml" />
<webflow:flow-location path="classpath:org/springframework/samples/springtravel/hotel/booking/booking.xml" />
<webflow:flow-location path="WEB-INF/controllers/hotel/search/search.xml" />
<webflow:flow-location path="WEB-INF/controllers/hotel/booking/booking.xml" />
</webflow:flow-registry>
<!-- Enables the flow JSF integration -->

View File

@@ -1,9 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- Enables annotation based configuration for @Transactional, @Repository, and @PersistenceContext -->
<context:component-scan base-package="org.springframework.samples.springtravel.hotel.booking"/>
<bean id="hotelBookingAgent" class="org.springframework.samples.springtravel.hotel.booking.impl.JpaHotelBookingAgent" />
<!-- Maps request URIs to controllers -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

View File

@@ -8,8 +8,7 @@
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<reference id="bookingAgent" interface="org.springframework.samples.springtravel.hotel.BookingAgent" />
<reference id="transactionManager" interface="org.springframework.orm.jpa.JpaTransactionManager" />
<reference id="entityManagerFactory" interface="javax.persistence.EntityManagerFactory" />
<reference id="dataSource" interface="javax.sql.DataSource" />
<reference id="hotelSearchAgent" interface="org.springframework.samples.springtravel.hotel.search.HotelSearchAgent" />
</beans:beans>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<!-- Instructs Spring to perfrom declarative transaction managemenet on annotated classes -->
<tx:annotation-driven />
<!-- Drives local transactions using the JPA API -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- Creates a EntityManagerFactory for use with the Hibernate JPA provider -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
</bean>
</beans>

View File

@@ -10,7 +10,7 @@
<!-- Configure Spring Security -->
<security:http auto-config="true">
<security:form-login login-page="/spring/login" login-processing-url="/spring/loginProcess" default-target-url="/spring/hotel/search" authentication-failure-url="/spring/login?login_error=1" />
<security:form-login login-page="/spring/login" login-processing-url="/spring/loginProcess" default-target-url="/spring/main" authentication-failure-url="/spring/login?login_error=1" />
<security:logout logout-url="/spring/logout" logout-success-url="/spring/logoutSuccess" />
</security:http>
@@ -33,4 +33,4 @@
</security:user-service>
</security:authentication-provider>
</beans>
</beans>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<secured attributes="ROLE_USER" />
<persistence-context/>
<input name="hotelId" required="true"/>
<on-start>
<evaluate expression="hotelSearchAgent.findHotelById(hotelId)" result="flowScope.hotel" />
<evaluate expression="hotelBookingAgent.createBooking(hotel, currentUser.name)" result="flowScope.booking" />
</on-start>
<view-state id="enterBookingDetails" model="booking">
<transition on="proceed" to="reviewBooking"/>
<transition on="cancel" to="bookingCancelled" bind="false"/>
</view-state>
<view-state id="reviewBooking">
<transition on="confirm" to="bookingConfirmed">
<evaluate expression="persistenceContext.persist(booking)" />
</transition>
<transition on="revise" to="enterBookingDetails" />
<transition on="cancel" to="bookingCancelled" />
</view-state>
<end-state id="bookingConfirmed" commit="true" />
<end-state id="bookingCancelled" />
</flow>

View File

@@ -0,0 +1,136 @@
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:sf="http://www.springframework.org/tags/faces"
template="/WEB-INF/layouts/standard.xhtml">
<ui:define name="content">
<div class="section">
<h2>Book Hotel</h2>
<ui:fragment id="messages">
<div id="messagesInsertionPoint">
<h:messages errorClass="errors" />
</div>
</ui:fragment>
<h:form id="bookingForm">
<fieldset>
<div class="field">
<div class="label">Name:</div>
<div class="output">#{booking.hotel.name}</div>
</div>
<div class="field">
<div class="label">Address:</div>
<div class="output">#{booking.hotel.address}</div>
</div>
<div class="field">
<div class="label">City, State:</div>
<div class="output">#{booking.hotel.city}, #{booking.hotel.state}</div>
</div>
<div class="field">
<div class="label">Zip:</div>
<div class="output">#{booking.hotel.zip}</div>
</div>
<div class="field">
<div class="label">Country:</div>
<div class="output">#{booking.hotel.country}</div>
</div>
<div class="field">
<div class="label">Nightly rate:</div>
<div class="output">
<h:outputText value="#{booking.hotel.price}">
<f:convertNumber type="currency" currencySymbol="$"/>
</h:outputText>
</div>
</div>
<div class="field">
<div class="label">
<h:outputLabel for="checkinDate">Check In Date:</h:outputLabel>
</div>
<div class="input">
<sf:clientDateValidator required="true" >
<h:inputText id="checkinDate" value="#{booking.checkinDate}" required="true">
<f:convertDateTime pattern="yyyy-MM-dd" timeZone="EST"/>
</h:inputText>
</sf:clientDateValidator>
</div>
</div>
<div class="field">
<div class="label">
<h:outputLabel for="checkoutDate">Check Out Date:</h:outputLabel>
</div>
<div class="input">
<sf:clientDateValidator required="true">
<h:inputText id="checkoutDate" value="#{booking.checkoutDate}" required="true">
<f:convertDateTime pattern="yyyy-MM-dd" timeZone="EST"/>
</h:inputText>
</sf:clientDateValidator>
</div>
</div>
<div class="field">
<div class="label">
<h:outputLabel for="beds">Room Preference:</h:outputLabel>
</div>
<div class="input">
<h:selectOneMenu id="beds" value="#{booking.beds}">
<f:selectItems value="#{referenceData.bedOptions}"/>
</h:selectOneMenu>
</div>
</div>
<div class="field">
<div class="label">
<h:outputLabel for="smoking">Smoking Preference:</h:outputLabel>
</div>
<div id="radio" class="input">
<h:selectOneRadio id="smoking" value="#{booking.smoking}" layout="pageDirection">
<f:selectItems value="#{referenceData.smokingOptions}"/>
</h:selectOneRadio>
</div>
</div>
<div class="field">
<div class="label">
<h:outputLabel for="creditCard">Credit Card #:</h:outputLabel>
</div>
<div class="input">
<sf:clientTextValidator required="true" regExp="[0-9]{16}" invalidMessage="A 16-digit credit card number is required.">
<h:inputText id="creditCard" value="#{booking.creditCard}" required="true"/>
</sf:clientTextValidator>
</div>
</div>
<div class="field">
<div class="label">
<h:outputLabel for="creditCardName">Credit Card Name:</h:outputLabel>
</div>
<div class="input">
<sf:clientTextValidator required="true">
<h:inputText id="creditCardName" value="#{booking.creditCardName}" required="true"/>
</sf:clientTextValidator>
</div>
</div>
<div class="field">
<div class="label">
<h:outputLabel for="creditCardExpiryMonth">Expiration Date:</h:outputLabel>
</div>
<div class="input">
<h:selectOneMenu id="creditCardExpiryMonth" value="#{booking.creditCardExpiryMonth}">
<f:selectItems value="#{referenceData.creditCardExpMonths}" />
</h:selectOneMenu>
<h:selectOneMenu id="creditCardExpiryYear" value="#{booking.creditCardExpiryYear}">
<f:selectItems value="#{referenceData.creditCardExpYears}"/>
</h:selectOneMenu>
</div>
</div>
<div class="buttonGroup">
<sf:validateAllOnClick>
<sf:commandButton id="proceed" action="proceed" processIds="*" value="Proceed"/>&#160;
</sf:validateAllOnClick>
<sf:commandButton id="cancel" value="Cancel" action="cancel"/>
</div>
</fieldset>
</h:form>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,2 @@
booking.checkinDate.beforeToday=The Check In Date must be a future date
booking.checkoutDate.beforeCheckinDate=The Check Out Date must be later than the Check In Date

View File

@@ -0,0 +1,76 @@
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:sf="http://www.springframework.org/tags/faces"
template="/WEB-INF/layouts/standard.xhtml">
<ui:define name="content">
<div class="section">
<h1>Confirm Hotel Booking</h1>
</div>
<div class="section">
<h:form id="confirm">
<fieldset>
<div class="field">
<div class="label">Name:</div>
<div class="output">#{booking.hotel.name}</div>
</div>
<div class="field">
<div class="label">Address:</div>
<div class="output">#{booking.hotel.address}</div>
</div>
<div class="field">
<div class="label">City, State:</div>
<div class="output">#{booking.hotel.city}, #{booking.hotel.state}</div>
</div>
<div class="field">
<div class="label">Zip:</div>
<div class="output">#{booking.hotel.zip}</div>
</div>
<div class="field">
<div class="label">Country:</div>
<div class="output">#{booking.hotel.country}</div>
</div>
<div class="field">
<div class="label">Total payment:</div>
<div class="output">
<h:outputText value="#{booking.total}">
<f:convertNumber type="currency" currencySymbol="$"/>
</h:outputText>
</div>
</div>
<div class="field">
<div class="label">Check In Date:</div>
<div class="output">
<h:outputText value="#{booking.checkinDate}">
<f:convertDateTime dateStyle="short"/>
</h:outputText>
</div>
</div>
<div class="field">
<div class="label">Check Out Date:</div>
<div class="output">
<h:outputText value="#{booking.checkoutDate}">
<f:convertDateTime dateStyle="short"/>
</h:outputText>
</div>
</div>
<div class="field">
<div class="label">Credit Card #:</div>
<div class="output">#{booking.creditCard}</div>
</div>
<div class="buttonGroup">
<h:commandButton id="confirm" value="Confirm" action="confirm"/>&#160;
<h:commandButton id="revise" value="Revise" action="revise"/>&#160;
<h:commandButton id="cancel" value="Cancel" action="cancel"/>
</div>
</fieldset>
</h:form>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,91 @@
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:sf="http://www.springframework.org/tags/faces"
template="/WEB-INF/layouts/standard.xhtml">
<ui:define name="content">
<ui:fragment id="hotelSearchFragment">
<div id="hotelSearch" class="section">
<span class="errors">
<h:messages globalOnly="true" />
</span>
<h2>Search Hotels</h2>
<h:form id="mainForm">
<fieldset>
<div class="field">
<div class="label">
<h:outputLabel for="searchString">Search String:</h:outputLabel>
</div>
<div class="input">
<sf:clientTextValidator promptMessage="Search hotels by name, address, city, or zip.">
<h:inputText id="searchString" value="#{searchCriteria.searchString}" />
</sf:clientTextValidator>
</div>
</div>
<div class="field">
<div class="label">
<h:outputLabel for="pageSize">Maximum results:</h:outputLabel>
</div>
<div class="input">
<h:selectOneMenu id="pageSize" value="#{searchCriteria.pageSize}">
<f:selectItems value="#{referenceData.pageSizeOptions}" />
</h:selectOneMenu>
</div>
</div>
<div class="buttonGroup">
<sf:commandButton id="findHotels" value="Find Hotels" processIds="*" action="search" />
</div>
</fieldset>
</h:form>
</div>
</ui:fragment>
<ui:fragment id="bookingsFragment">
<div id="bookingsSection" class="section">
<h:form id="bookingsForm">
<h2>Current Hotel Bookings</h2>
<h:outputText value="No Bookings Found" rendered="#{bookings.rowCount == 0}"/>
<h:dataTable id="bookings" styleClass="summary" value="#{bookings}" var="booking" rendered="#{bookings.rowCount > 0}">
<h:column>
<f:facet name="header">Name</f:facet>
#{booking.hotel.name}
</h:column>
<h:column>
<f:facet name="header">Address</f:facet>
#{booking.hotel.address}
</h:column>
<h:column>
<f:facet name="header">City, State</f:facet>
#{booking.hotel.city}, #{booking.hotel.state}
</h:column>
<h:column>
<f:facet name="header">Check in date</f:facet>
<h:outputText value="#{booking.checkinDate}">
<f:convertDateTime dateStyle="short"/>
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">Check out date</f:facet>
<h:outputText value="#{booking.checkoutDate}">
<f:convertDateTime dateStyle="short"/>
</h:outputText>
</h:column>
<h:column>
<f:facet name="header">Confirmation number</f:facet>
#{booking.id}
</h:column>
<h:column>
<f:facet name="header">Action</f:facet>
<sf:commandLink id="cancel" value="Cancel" processIds="bookingsFragment" action="cancelBooking" />
</h:column>
</h:dataTable>
</h:form>
</div>
</ui:fragment>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,56 @@
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:sf="http://www.springframework.org/tags/faces"
template="/WEB-INF/layouts/standard.xhtml">
<ui:define name="content">
<div class="section">
<h2>View Hotel</h2>
<h:form id="hotel">
<fieldset>
<div class="field">
<div class="label">Name:</div>
<div class="output">#{hotel.name}</div>
</div>
<div class="field">
<div class="label">Address:</div>
<div class="output">#{hotel.address}</div>
</div>
<div class="field">
<div class="label">City:</div>
<div class="output">#{hotel.city}</div>
</div>
<div class="field">
<div class="label">State:</div>
<div class="output">#{hotel.state}</div>
</div>
<div class="field">
<div class="label">Zip:</div>
<div class="output">#{hotel.zip}</div>
</div>
<div class="field">
<div class="label">Country:</div>
<div class="output">#{hotel.country}</div>
</div>
<div class="field">
<div class="label">Nightly rate:</div>
<div class="output">
<h:outputText value="#{hotel.price}">
<f:convertNumber type="currency" currencySymbol="$"/>
</h:outputText>
</div>
</div>
<div class="buttonGroup">
<h:commandButton id="book" action="book" value="Book Hotel"/>&#160;
<h:commandButton id="cancel" action="cancel" value="Back to Search"/>
</div>
</fieldset>
</h:form>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,51 @@
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:sf="http://www.springframework.org/tags/faces"
template="/WEB-INF/layouts/standard.xhtml">
<ui:define name="content">
<h:form id="hotels">
<div class="section">
<h2>Hotel Results</h2>
<p>
<sf:commandLink value="Change Search" action="changeSearch"/>
</p>
<ui:fragment id="searchResultsFragment">
<div id="searchResults">
<h:outputText id="noHotelsText" value="No Hotels Found" rendered="#{hotels.rowCount == 0}"/>
<h:dataTable id="hotels" styleClass="summary" value="#{hotels}" var="h" rendered="#{hotels.rowCount > 0}">
<h:column>
<f:facet name="header">Name</f:facet>
#{h.name}
</h:column>
<h:column>
<f:facet name="header">Address</f:facet>
#{h.address}
</h:column>
<h:column>
<f:facet name="header">City, State</f:facet>
#{h.city}, #{h.state}, #{h.country}
</h:column>
<h:column>
<f:facet name="header">Zip</f:facet>
#{h.zip}
</h:column>
<h:column>
<f:facet name="header">Action</f:facet>
<sf:commandLink id="viewHotelLink" value="View Hotel" action="select"/>
</h:column>
</h:dataTable>
<div class="buttonGroup">
<sf:commandLink id="previousPageLink" value="Previous results" action="previous" rendered="#{searchCriteria.page > 0}"/>
<sf:commandLink id="nextPageLink" value="More Results" action="next" rendered="#{not empty hotels and hotels.rowCount == searchCriteria.pageSize}"/>
</div>
</div>
</ui:fragment>
</div>
</h:form>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<var name="searchCriteria" class="org.springframework.samples.springtravel.hotel.search.SearchCriteria" />
<view-state id="enterSearchCriteria">
<on-render>
<evaluate expression="hotelBookingAgent.findBookings(currentUser.name)" result="viewScope.bookings" result-type="dataModel" />
</on-render>
<transition on="search" to="reviewHotels">
<evaluate expression="searchCriteria.resetPage()"/>
</transition>
<transition on="cancelBooking">
<evaluate expression="hotelBookingAgent.cancelBooking(bookings.selectedRow.id)" />
<render fragments="bookingsFragment"/>
</transition>
</view-state>
<view-state id="reviewHotels">
<on-render>
<evaluate expression="hotelSearchAgent.findHotels(searchCriteria)" result="viewScope.hotels" result-type="dataModel" />
</on-render>
<transition on="previous">
<evaluate expression="searchCriteria.previousPage()" />
<render fragments="hotels:searchResultsFragment" />
</transition>
<transition on="next">
<evaluate expression="searchCriteria.nextPage()" />
<render fragments="hotels:searchResultsFragment" />
</transition>
<transition on="select" to="reviewHotel">
<set name="flowScope.hotel" value="hotels.selectedRow" />
</transition>
<transition on="changeSearch" to="changeSearchCriteria" />
</view-state>
<view-state id="reviewHotel">
<transition on="book" to="bookHotel" />
<transition on="cancel" to="enterSearchCriteria" />
</view-state>
<subflow-state id="bookHotel" subflow="booking">
<input name="hotelId" value="hotel.id" />
<transition on="bookingConfirmed" to="finish" />
<transition on="bookingCancelled" to="enterSearchCriteria" />
</subflow-state>
<view-state id="changeSearchCriteria" view="enterSearchCriteria.xhtml" popup="true">
<on-entry>
<render fragments="hotelSearchFragment" />
</on-entry>
<transition on="search" to="reviewHotels">
<evaluate expression="searchCriteria.resetPage()"/>
</transition>
</view-state>
<end-state id="finish" />
</flow>