diff --git a/spring-webflow-samples/booking-jsf/.springBeans b/spring-webflow-samples/booking-jsf/.springBeans index 7df5daff..eebf60ca 100755 --- a/spring-webflow-samples/booking-jsf/.springBeans +++ b/spring-webflow-samples/booking-jsf/.springBeans @@ -1,13 +1,14 @@ - - xml - + 1 + + + + + src/main/webapp/WEB-INF/config/application-layer-config.xml src/main/webapp/WEB-INF/config/web-application-config.xml - src/main/webapp/flow/main/main-beans.xml - src/main/webapp/flow/booking/booking-beans.xml @@ -24,7 +25,6 @@ true false - src/main/webapp/flow/booking/booking-beans.xml src/main/webapp/WEB-INF/config/application-layer-config.xml @@ -33,7 +33,6 @@ true false - src/main/webapp/flow/main/main-beans.xml src/main/webapp/WEB-INF/config/application-layer-config.xml diff --git a/spring-webflow-samples/booking-jsf/src/main/java/META-INF/persistence.xml b/spring-webflow-samples/booking-jsf/src/main/java/META-INF/persistence.xml index 4ad486f6..f4e3d6a7 100755 --- a/spring-webflow-samples/booking-jsf/src/main/java/META-INF/persistence.xml +++ b/spring-webflow-samples/booking-jsf/src/main/java/META-INF/persistence.xml @@ -5,9 +5,9 @@ version="1.0"> org.hibernate.ejb.HibernatePersistence - org.springframework.webflow.samples.booking.app.User - org.springframework.webflow.samples.booking.app.Booking - org.springframework.webflow.samples.booking.app.Hotel + org.springframework.webflow.samples.booking.User + org.springframework.webflow.samples.booking.Booking + org.springframework.webflow.samples.booking.Hotel diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/Booking.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/Booking.java similarity index 78% rename from spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/Booking.java rename to spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/Booking.java index 22edfe95..0e555cf7 100755 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/Booking.java +++ b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/Booking.java @@ -1,4 +1,4 @@ -package org.springframework.webflow.samples.booking.app; +package org.springframework.webflow.samples.booking; import java.io.Serializable; import java.math.BigDecimal; @@ -16,11 +16,17 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; +import org.springframework.binding.message.MessageBuilder; +import org.springframework.binding.message.MessageContext; + /** * A Hotel Booking made by a User. */ @Entity public class Booking implements Serializable { + + private static final long serialVersionUID = 1171567558348174963L; + private Long id; private User user; @@ -168,6 +174,18 @@ public class Booking implements Serializable { this.creditCardExpiryYear = creditCardExpiryYear; } + public void validate(MessageContext context) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DAY_OF_MONTH, -1); + if (checkinDate.before(calendar.getTime())) { + context.addMessage(new MessageBuilder().source("checkinDate").defaultText( + "Check in date must be a future date").error().build()); + } else if (!checkinDate.before(checkoutDate)) { + context.addMessage(new MessageBuilder().source("checkoutDate").defaultText( + "Check out date must be later than check in date").error().build()); + } + } + @Override public String toString() { return "Booking(" + user + "," + hotel + ")"; diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/BookingService.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/BookingService.java similarity index 60% rename from spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/BookingService.java rename to spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/BookingService.java index 80b3b023..68c8a114 100755 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/BookingService.java +++ b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/BookingService.java @@ -1,4 +1,4 @@ -package org.springframework.webflow.samples.booking.app; +package org.springframework.webflow.samples.booking; import java.util.List; @@ -17,12 +17,10 @@ public interface BookingService { /** * Find hotels available for booking by some criteria. - * @param searchString the search query string to filter hotels by name - * @param pageSize the page size - * @param page the current page - * @return a list of hotels not exceeding the page size + * @param criteria the search criteria + * @return a list of hotels meeting the criteria */ - public List findHotels(String searchString, int pageSize, int page); + public List findHotels(SearchCriteria criteria); /** * Find hotels by their identifier. @@ -31,6 +29,14 @@ public interface BookingService { */ public Hotel findHotelById(Long id); + /** + * Returns a new booking object attached to the current persistence context. + * @param hotel the hotel being booked + * @param user the user performing the booking + * @return the booking + */ + public Booking createBooking(Hotel hotel, User user); + /** * Cancel an existing booking. * @param id the booking id diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/Hotel.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/Hotel.java similarity index 92% rename from spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/Hotel.java rename to spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/Hotel.java index bef830c5..4e28670f 100755 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/Hotel.java +++ b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/Hotel.java @@ -1,4 +1,4 @@ -package org.springframework.webflow.samples.booking.app; +package org.springframework.webflow.samples.booking; import java.io.Serializable; import java.math.BigDecimal; @@ -13,6 +13,9 @@ import javax.persistence.Id; */ @Entity public class Hotel implements Serializable { + + private static final long serialVersionUID = 4011346719502656269L; + private Long id; private String name; diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/JpaBookingService.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/JpaBookingService.java similarity index 68% rename from spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/JpaBookingService.java rename to spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/JpaBookingService.java index a4a92f19..b48161ae 100755 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/JpaBookingService.java +++ b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/JpaBookingService.java @@ -1,4 +1,4 @@ -package org.springframework.webflow.samples.booking.app; +package org.springframework.webflow.samples.booking; import java.util.List; @@ -7,7 +7,6 @@ import javax.persistence.PersistenceContext; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.StringUtils; /** * A JPA-based implementation of the Booking Service. Delegates to a JPA entity manager to issue data access calls @@ -33,13 +32,12 @@ public class JpaBookingService implements BookingService { @Transactional(readOnly = true) @SuppressWarnings("unchecked") - public List findHotels(String searchString, int pageSize, int page) { - String pattern = !StringUtils.hasText(searchString) ? "'%'" : "'%" - + searchString.toLowerCase().replace('*', '%') + "%'"; + public List findHotels(SearchCriteria criteria) { + String pattern = getSearchPattern(criteria); return em.createQuery( "select h from Hotel h where lower(h.name) like " + pattern + " or lower(h.city) like " + pattern + " or lower(h.zip) like " + pattern + " or lower(h.address) like " + pattern).setMaxResults( - pageSize).setFirstResult(page * pageSize).getResultList(); + criteria.getPageSize()).setFirstResult(criteria.getPage() * criteria.getPageSize()).getResultList(); } @Transactional(readOnly = true) @@ -47,7 +45,15 @@ public class JpaBookingService implements BookingService { return em.find(Hotel.class, id); } - // this one is a read/write transaction + // read-write transactional methods + + @Transactional + public Booking createBooking(Hotel hotel, User user) { + Booking booking = new Booking(hotel, user); + em.persist(booking); + return booking; + } + @Transactional public void cancelBooking(Long id) { Booking booking = em.find(Booking.class, id); @@ -55,4 +61,15 @@ public class JpaBookingService implements BookingService { em.remove(booking); } } + + // helpers + + private String getSearchPattern(SearchCriteria criteria) { + if (criteria.getSearchString().length() > 0) { + return "'%'" + criteria.getSearchString().toLowerCase().replace('*', '%') + "%'"; + } else { + return "'%"; + } + } + } \ No newline at end of file diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/User.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/User.java similarity index 83% rename from spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/User.java rename to spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/User.java index ee436b92..494e9ddd 100755 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/app/User.java +++ b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/User.java @@ -1,4 +1,4 @@ -package org.springframework.webflow.samples.booking.app; +package org.springframework.webflow.samples.booking; import java.io.Serializable; @@ -12,6 +12,9 @@ import javax.persistence.Table; @Entity @Table(name = "Customer") public class User implements Serializable { + + private static final long serialVersionUID = -3652559447682574722L; + private String username; private String password; diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/booking/BookingActions.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/booking/BookingActions.java deleted file mode 100644 index f93337ee..00000000 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/booking/BookingActions.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.springframework.webflow.samples.booking.flow.booking; - -import java.util.Calendar; - -import javax.persistence.EntityManager; - -import org.springframework.binding.message.MessageBuilder; -import org.springframework.webflow.action.MultiAction; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.samples.booking.app.Booking; -import org.springframework.webflow.samples.booking.app.Hotel; -import org.springframework.webflow.samples.booking.app.User; - -/** - * Actions invoked by the booking flow. These actions are extensions of the flow definition, called by the flow - * definition at the appropriate points. Actions allow an externalized flow definition to delegate out to Java code to - * perform processing. - */ -public class BookingActions extends MultiAction { - - /** - * Create a new booking object and register it with the flow-managed entity manager. The booking is not actually - * flushed to the database at this time; that only occurs when the booking flow reaches its "bookingAuthorized" - * end-state, which is a "commit" state. - * - * It is expected a future milestone of Spring Web Flow 2.0 will support Flows being defined fully in Java and - * Groovy, allowing logic like this to be defined with the flow definition and without the attribute lookup code you - * see here. - * @param context the current flow execution request context - * @return success if the booking was created successfully. - */ - public Event createBooking(RequestContext context) { - Hotel hotel = (Hotel) context.getFlowScope().get("hotel"); - User user = (User) context.getConversationScope().get("user"); - Booking booking = new Booking(hotel, user); - EntityManager em = (EntityManager) context.getFlowScope().get("entityManager"); - em.persist(booking); - context.getFlowScope().put("booking", booking); - return success(); - } - - /** - * Perform some custom server-side validation on the flow-scoped Booking object updated by the booking form. - * - * It is expected a future milestone of Spring Web Flow 2.0 will add a Messages abstraction that decouples SWF - * artifacts from environment-specific constructs like the FacesContext. - * @param context the current flow execution request context - * @return success if validation was successful, error if not - */ - public Event validateBooking(RequestContext context) { - Booking booking = (Booking) context.getFlowScope().get("booking"); - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.DAY_OF_MONTH, -1); - if (booking.getCheckinDate().before(calendar.getTime())) { - context.getMessageContext().addMessage( - new MessageBuilder().source("checkinDate").defaultText("Check in date must be a future date") - .error().build()); - return error(); - } else if (!booking.getCheckinDate().before(booking.getCheckoutDate())) { - context.getMessageContext().addMessage( - new MessageBuilder().source("checkoutDate").defaultText( - "Check out date must be later than check in date").error().build()); - return error(); - } - return success(); - } -} diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/booking/BookingOptions.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/booking/BookingOptions.java deleted file mode 100644 index 4c07aa3b..00000000 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/booking/BookingOptions.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.springframework.webflow.samples.booking.flow.booking; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import javax.faces.model.SelectItem; - -public class BookingOptions implements Serializable { - - private List bedOptions; - - private List smokingOptions; - - private List creditCardExpMonths; - - private List creditCardExpYears; - - public List getBedOptions() { - if (bedOptions == null) { - bedOptions = new ArrayList(); - 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 getSmokingOptions() { - if (smokingOptions == null) { - smokingOptions = new ArrayList(); - smokingOptions.add(new SelectItem(Boolean.TRUE, "Smoking")); - smokingOptions.add(new SelectItem(Boolean.FALSE, "Non-Smoking")); - } - return smokingOptions; - } - - public List getCreditCardExpMonths() { - if (creditCardExpMonths == null) { - creditCardExpMonths = new ArrayList(); - 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 getCreditCardExpYears() { - if (creditCardExpYears == null) { - creditCardExpYears = new ArrayList(); - creditCardExpYears.add(new SelectItem(new Integer(2005), "2005")); - creditCardExpYears.add(new SelectItem(new Integer(2006), "2006")); - creditCardExpYears.add(new SelectItem(new Integer(2007), "2007")); - creditCardExpYears.add(new SelectItem(new Integer(2008), "2008")); - creditCardExpYears.add(new SelectItem(new Integer(2009), "2009")); - creditCardExpYears.add(new SelectItem(new Integer(2010), "2010")); - } - return creditCardExpYears; - } - -} diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/main/MainActions.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/main/MainActions.java deleted file mode 100644 index f1899dea..00000000 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/main/MainActions.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.springframework.webflow.samples.booking.flow.main; - -import org.springframework.webflow.action.MultiAction; -import org.springframework.webflow.execution.Event; -import org.springframework.webflow.execution.RequestContext; -import org.springframework.webflow.samples.booking.app.BookingService; -import org.springframework.webflow.samples.booking.app.User; - -/** - * Actions invoked by the main flow. These actions are extensions of the flow definition, called by the flow definition - * at the appropriate points. Actions allow an externalized flow definition to delegate out to Java code to perform - * processing. - */ -public class MainActions extends MultiAction { - - private BookingService bookingService; - - /** - * Constructs a new multi-action for the main flow that will delegate to the provided booking service - * @param bookingService the booking service - */ - public MainActions(BookingService bookingService) { - this.bookingService = bookingService; - } - - /** - * Simply put a dummy user in conversation scope to simulate a user login. In the future this sample may add user - * authentication support. - * @param context the current flow execution request context - * @return success - */ - public Event initCurrentUser(RequestContext context) { - User user = new User("springer", "springrocks", "Springer"); - context.getConversationScope().put("user", user); - return success(); - } -} diff --git a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/main/SearchCriteria.java b/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/main/SearchCriteria.java deleted file mode 100755 index 7078a229..00000000 --- a/spring-webflow-samples/booking-jsf/src/main/java/org/springframework/webflow/samples/booking/flow/main/SearchCriteria.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.springframework.webflow.samples.booking.flow.main; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import javax.faces.event.ActionEvent; -import javax.faces.model.SelectItem; - -import org.springframework.util.StringUtils; -import org.springframework.webflow.samples.booking.app.BookingService; - -/** - * A backing bean for the main hotel search form. Encapsulates the criteria needed to perform a hotel search. - * - * It is expected a future milestone of Spring Web Flow 2.0 will allow flow-scoped beans like this one to hold - * references to transient services that are restored automatically when the flow is resumed on subsequent requests. - * This would allow this SearchCriteria object to delegate to the {@link BookingService} directly, for example, - * eliminating the need for the actions in {@link MainActions}. - */ -public class SearchCriteria implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * The user-provided search criteria for finding Hotels. - */ - private String searchString; - - /** - * The maximum page size of the Hotel result list - */ - private int pageSize = 5; - - /** - * The current page of the Hotel result list. - */ - private int page; - - /** - * The available page size options. - */ - private List pageSizeOptions; - - /** - * Increase the current page - */ - public void nextPage() { - page++; - } - - /** - * Decrease the current page - */ - public void prevPage() { - page--; - } - - /** - * Signal that a find is about to occur and reset the page size to 0. - */ - public void findHotelsListener(ActionEvent event) { - page = 0; - } - - public String getSearchString() { - return searchString; - } - - public void setSearchString(String searchString) { - this.searchString = searchString; - } - - public int getPageSize() { - return pageSize; - } - - public void setPageSize(int pageSize) { - this.pageSize = pageSize; - } - - public int getPage() { - return page; - } - - public void setPage(int page) { - this.page = page; - } - - public List getPageSizeOptions() { - if (pageSizeOptions == null) { - pageSizeOptions = new ArrayList(); - 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; - } - - public String toString() { - StringBuffer criteria = new StringBuffer(); - if (StringUtils.hasText(searchString)) { - criteria.append("Text: " + searchString + ", "); - } - criteria.append("Page Size: " + pageSize); - return criteria.toString(); - } - -} diff --git a/spring-webflow-samples/booking-jsf/src/main/webapp/WEB-INF/config/application-layer-config.xml b/spring-webflow-samples/booking-jsf/src/main/webapp/WEB-INF/config/application-layer-config.xml index caa231ac..b9666992 100755 --- a/spring-webflow-samples/booking-jsf/src/main/webapp/WEB-INF/config/application-layer-config.xml +++ b/spring-webflow-samples/booking-jsf/src/main/webapp/WEB-INF/config/application-layer-config.xml @@ -9,7 +9,7 @@ http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> - + diff --git a/spring-webflow-samples/booking-jsf/src/main/webapp/WEB-INF/flow/booking/booking.xml b/spring-webflow-samples/booking-jsf/src/main/webapp/WEB-INF/flow/booking/booking.xml index a67e7132..faff5a62 100755 --- a/spring-webflow-samples/booking-jsf/src/main/webapp/WEB-INF/flow/booking/booking.xml +++ b/spring-webflow-samples/booking-jsf/src/main/webapp/WEB-INF/flow/booking/booking.xml @@ -12,10 +12,8 @@ --> - - - + @@ -26,12 +24,13 @@ - + + diff --git a/spring-webflow-samples/booking-jsf/src/main/webapp/intro.xhtml b/spring-webflow-samples/booking-jsf/src/main/webapp/intro.xhtml index b51eda13..41c36085 100755 --- a/spring-webflow-samples/booking-jsf/src/main/webapp/intro.xhtml +++ b/spring-webflow-samples/booking-jsf/src/main/webapp/intro.xhtml @@ -6,12 +6,12 @@ Spring Faces: Hotel Booking Sample Application