views:

26

answers:

0

Hello,

I've been playing around with the spring web flow hotel booking application and have extended it a bit to try to get a better understanding of how spring web flow and JSF integrate together. The spring documentation isn't that great in this area and it has been my impression that things work until you change them and then there is no clear documentation describing how it worked in the first place so you don't know how you broke it.

Anyway, hopefully you're familiar with the spring web flow hotel booking sample application. If you're not, the main flow accepts search criteria and returns a list of hotels and then a hotel can be selected and then its information is displayed. I'm trying to extend it so that when you're looking at a hotel, you can then view information about individual hotel rooms.

here is the code for the flow:

    <view-state id="reviewHotels">
    <on-render>
        <evaluate expression="bookingService.findHotels(searchCriteria, flowRequestContext)" result="viewScope.hotels" result-type="dataModel" />
    </on-render>
    <transition on="select" to="reviewHotel">
        <set name="flowScope.hotel" value="hotels.selectedRow" />
    </transition>

When you select a hotel it calls a pricing service. Here is that view:

<view-state id="reviewHotel" model="hotel">
    <on-render>
        <evaluate expression="bookingService.priceHotel(flowScope.hotel, flowRequestContext)" result="flowScope.hotel"/>
    </on-render>

    <transition on="price" to="displayPriceBreakdown">
        <set name="flowScope.room" value="flowScope.hotel.rooms.selectedRow"></set>
    </transition>
</view-state>

The displayPriceBreakdown view then displays how the price was calculated when you click on a hotel price. Here is the view config:

    <view-state id="displayPriceBreakdown" view="displayPriceBreakdown.xhtml">
    <on-entry>
        <render fragments="priceBreakdownFragment" />
    </on-entry>
    <transition on="back" to="reviewHotel"/>
</view-state>

The reviewHotel.xhtml which shows the hotel details and its rooms looks like this:

<ui:define name="content">
<div class="section">
<h2>View Hotel</h2>
<ui:fragment id="messages">
        <div id="messagesInsertionPoint">
            <h:messages errorClass="errors" />
        </div>
</ui:fragment>

<h:form id="hotel">
    <fieldset>
        <div class="field">
            <div class="labelhotel">Name:</div>
            <div class="outputhotel">#{hotel.name}</div>
        </div>
        <div class="field">
            <div class="labelhotel">Address:</div>
            <div class="outputhotel">#{hotel.address}</div>
        </div>
        <div class="field">
            <div class="labelhotel">City:</div>
            <div class="outputhotel">#{hotel.city}</div>
        </div>
        <div class="field">
            <div class="labelhotel">Post Code:</div>
            <div class="outputhotel">#{hotel.zip}</div>
        </div>
        <div class="field">
            <div class="labelhotel">Country:</div>
            <div class="outputhotel">#{hotel.country}</div>
        </div>
        <div class="field">
            <div class="labelhotel">Amenities:</div>
            <div class="outputhotel"><h:dataTable id="amentities" var="a" value="#{hotel.amenities}">
                                    <h:column>#{a.name} - #{a.description}</h:column></h:dataTable></div>
        </div>

        <div class="field">
            <div class="labelhotel">Rooms:</div>
            <ui:fragment id="roomsFragment">
            <div class="outputhotel"><h:dataTable id="rooms" styleClass="summary" var="r" value="#{hotel.rooms}">
                                    <h:column>#{r.roomType} - #{r.bedType}</h:column> 
                                    <h:column><sf:commandLink id="priceBreakdownLink" value="#{r.roomPrice} #{r.roomPriceCurrency}" action="price" processIds="priceBreakdownFragment"/> </h:column>
                                    <h:column><sf:commandLink id="bookHotelLink" value="Book Hotel" action="select"/></h:column>
                                </h:dataTable>
            </div>
            </ui:fragment>
        </div>

        <div class="buttonGroup">
            <h:commandButton id="cancel" action="cancel" value="Back to Search"/>
        </div>
    </fieldset>
</h:form>

with the important bit being the dataTable used to display the hotel rooms:

            <div class="field">
            <div class="labelhotel">Rooms:</div>
            <ui:fragment id="roomsFragment">
            <div class="outputhotel"><h:dataTable id="rooms" styleClass="summary" var="r" value="#{hotel.rooms}">
                                    <h:column>#{r.roomType} - #{r.bedType}</h:column> 
                                    <h:column><sf:commandLink id="priceBreakdownLink" value="#{r.roomPrice} #{r.roomPriceCurrency}" action="price" processIds="priceBreakdownFragment"/> </h:column>
                                    <h:column><sf:commandLink id="bookHotelLink" value="Book Hotel" action="select"/></h:column>
                                </h:dataTable>
            </div>
            </ui:fragment>
        </div>

The room information displays correctly however when the user clicks on a price then I want to show the price breakdown list for the particular room that was selected. That is what I was hoping to accomplish with the:

        <transition on="price" to="displayPriceBreakdown">
        <set name="flowScope.room" value="flowScope.hotel.rooms.selectedRow"></set>
    </transition>

However when I run I get a NumberFormatException for selectedRow.

HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@34f67 targetAction = [SetAction@4db694 name = flowScope.room, value = flowScope.hotel.rooms.selectedRow, type = [null]], attributes = map[[empty]]] in state 'reviewHotel' of flow 'main' -- action execution attributes were 'map[[empty]]' org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:583) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511) javax.servlet.http.HttpServlet.service(HttpServlet.java:637) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) root cause

org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@34f67 targetAction = [SetAction@4db694 name = flowScope.room, value = flowScope.hotel.rooms.selectedRow, type = [null]], attributes = map[[empty]]] in state 'reviewHotel' of flow 'main' -- action execution attributes were 'map[[empty]]' org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:60) org.springframework.webflow.engine.support.ActionTransitionCriteria.test(ActionTransitionCriteria.java:82) org.springframework.webflow.engine.support.TransitionCriteriaChain.test(TransitionCriteriaChain.java:71) org.springframework.webflow.engine.Transition.canExecute(Transition.java:195) org.springframework.webflow.engine.Transition.execute(Transition.java:211) org.springframework.webflow.engine.impl.FlowExecutionImpl.execute(FlowExecutionImpl.java:391) org.springframework.webflow.engine.impl.RequestControlContextImpl.execute(RequestControlContextImpl.java:214) org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:119) org.springframework.webflow.engine.Flow.handleEvent(Flow.java:555) org.springframework.webflow.engine.impl.FlowExecutionImpl.handleEvent(FlowExecutionImpl.java:386) org.springframework.webflow.engine.impl.RequestControlContextImpl.handleEvent(RequestControlContextImpl.java:210) org.springframework.webflow.engine.ViewState.handleEvent(ViewState.java:230) org.springframework.webflow.engine.ViewState.resume(ViewState.java:196) org.springframework.webflow.engine.Flow.resume(Flow.java:545) org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259) org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:163) org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:183) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511) javax.servlet.http.HttpServlet.service(HttpServlet.java:637) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) root cause

java.lang.NumberFormatException: For input string: "selectedRow" java.lang.NumberFormatException.forInputString(NumberFormatException.java:48) java.lang.Integer.parseInt(Integer.java:449) java.lang.Integer.parseInt(Integer.java:499) javax.el.ListELResolver.coerce(ListELResolver.java:166) javax.el.ListELResolver.getValue(ListELResolver.java:51) javax.el.CompositeELResolver.getValue(CompositeELResolver.java:54) org.springframework.binding.expression.el.DefaultELResolver.getValue(DefaultELResolver.java:80) org.jboss.el.parser.AstPropertySuffix.getValue(AstPropertySuffix.java:53) org.jboss.el.parser.AstValue.getValue(AstValue.java:67) org.jboss.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186) org.springframework.binding.expression.el.BindingValueExpression.getValue(BindingValueExpression.java:54) org.springframework.binding.expression.el.ELExpression.getValue(ELExpression.java:54) org.springframework.webflow.action.SetAction.doExecute(SetAction.java:75) org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188) org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145) org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51) org.springframework.webflow.engine.support.ActionTransitionCriteria.test(ActionTransitionCriteria.java:82) org.springframework.webflow.engine.support.TransitionCriteriaChain.test(TransitionCriteriaChain.java:71) org.springframework.webflow.engine.Transition.canExecute(Transition.java:195) org.springframework.webflow.engine.Transition.execute(Transition.java:211) org.springframework.webflow.engine.impl.FlowExecutionImpl.execute(FlowExecutionImpl.java:391) org.springframework.webflow.engine.impl.RequestControlContextImpl.execute(RequestControlContextImpl.java:214) org.springframework.webflow.engine.TransitionableState.handleEvent(TransitionableState.java:119) org.springframework.webflow.engine.Flow.handleEvent(Flow.java:555) org.springframework.webflow.engine.impl.FlowExecutionImpl.handleEvent(FlowExecutionImpl.java:386) org.springframework.webflow.engine.impl.RequestControlContextImpl.handleEvent(RequestControlContextImpl.java:210) org.springframework.webflow.engine.ViewState.handleEvent(ViewState.java:230) org.springframework.webflow.engine.ViewState.resume(ViewState.java:196) org.springframework.webflow.engine.Flow.resume(Flow.java:545) org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259) org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:163) org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:183) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:511) javax.servlet.http.HttpServlet.service(HttpServlet.java:637) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:96) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

How should I pass the HotelRoom object into the displayPriceBreakdown fragment?

Many thanks if you've gotten this far and are reading and understanding this! I've tried to be as thorough as possible however if more information is needed please let me know.

Oh yes and Hotel as a variable called rooms which is a List and has getRooms : List and setRooms(List rooms) methods.