SWF-1367 Add support for JSF 2 Ajax requests, update booking-faces sample (JSF 2 based Ajax, jsr-303 validation), add chained delegation to AjaxHandlers, other miscellaneous improvements
This commit is contained in:
@@ -4,9 +4,11 @@ http://www.springframework.org/webflow
|
||||
|
||||
Changes in version 2.2.0.RELEASE ()
|
||||
-----------------------------------
|
||||
* Add support for handling JSF 2 resource requests (SWF-1366)
|
||||
* Add support for JSF 2 Ajax requests (SWF-1367)
|
||||
|
||||
|
||||
Changes in version 2.1.0.RELEASE (July 19, 2010)
|
||||
Changes in version 2.1.1.RELEASE (July 19, 2010)
|
||||
------------------------------------------------
|
||||
* Extract JSF 2 methods from FlowApplication into Jsf2FlowApplication (SWF-1261).
|
||||
* Fix handling of cascaded attributes in AjaxTilesView (SWF-1053).
|
||||
|
||||
@@ -17,47 +17,39 @@ package org.springframework.faces.richfaces;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.faces.FactoryFinder;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.FacesContextFactory;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.ajax4jsf.context.AjaxContext;
|
||||
import org.springframework.faces.webflow.FlowLifecycle;
|
||||
import org.springframework.faces.webflow.FacesContextHelper;
|
||||
import org.springframework.js.ajax.AbstractAjaxHandler;
|
||||
import org.springframework.js.ajax.AjaxHandler;
|
||||
import org.springframework.js.ajax.SpringJavascriptAjaxHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.support.WebApplicationObjectSupport;
|
||||
|
||||
/**
|
||||
* Ajax handler that works with Rich Faces, allowing support for Web Flow Ajax features with the Rich Faces toolkit.
|
||||
*
|
||||
* @see AbstractAjaxHandler
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
*/
|
||||
public class RichFacesAjaxHandler extends WebApplicationObjectSupport implements AjaxHandler {
|
||||
public class RichFacesAjaxHandler extends AbstractAjaxHandler implements AjaxHandler {
|
||||
|
||||
private AjaxHandler delegate = new SpringJavascriptAjaxHandler();
|
||||
|
||||
public boolean isAjaxRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (isRichFacesAjaxRequest(request, response)) {
|
||||
return true;
|
||||
} else {
|
||||
return delegate.isAjaxRequest(request, response);
|
||||
}
|
||||
/**
|
||||
* Create a RichFacesAjaxHandler that is not part of a chain of AjaxHandler's.
|
||||
*/
|
||||
public RichFacesAjaxHandler() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public void sendAjaxRedirect(String targetUrl, HttpServletRequest request, HttpServletResponse response,
|
||||
boolean popup) throws IOException {
|
||||
if (isRichFacesAjaxRequest(request, response)) {
|
||||
response.sendRedirect(response.encodeRedirectURL(targetUrl));
|
||||
} else {
|
||||
delegate.sendAjaxRedirect(targetUrl, request, response, popup);
|
||||
}
|
||||
/**
|
||||
* Create a RichFacesAjaxHandler as part of a chain of AjaxHandler's.
|
||||
*/
|
||||
public RichFacesAjaxHandler(AbstractAjaxHandler delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
protected boolean isRichFacesAjaxRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
protected boolean isAjaxRequestInternal(HttpServletRequest request, HttpServletResponse response) {
|
||||
FacesContextHelper helper = new FacesContextHelper();
|
||||
try {
|
||||
FacesContext facesContext = helper.getFacesContext(getServletContext(), request, response);
|
||||
@@ -68,33 +60,13 @@ public class RichFacesAjaxHandler extends WebApplicationObjectSupport implements
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
helper.cleanup();
|
||||
helper.releaseIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
private static class FacesContextHelper {
|
||||
|
||||
private boolean created = false;
|
||||
|
||||
protected FacesContext getFacesContext(ServletContext context, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
if (FacesContext.getCurrentInstance() != null) {
|
||||
return FacesContext.getCurrentInstance();
|
||||
} else {
|
||||
FacesContextFactory facesContextFactory = (FacesContextFactory) FactoryFinder
|
||||
.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
|
||||
FacesContext defaultFacesContext = facesContextFactory.getFacesContext(context, request, response,
|
||||
FlowLifecycle.newInstance());
|
||||
Assert.notNull(defaultFacesContext, "Creation of the default FacesContext failed.");
|
||||
created = true;
|
||||
return defaultFacesContext;
|
||||
}
|
||||
}
|
||||
|
||||
protected void cleanup() {
|
||||
if (created) {
|
||||
FacesContext.getCurrentInstance().release();
|
||||
}
|
||||
}
|
||||
protected void sendAjaxRedirectInternal(String targetUrl, HttpServletRequest request, HttpServletResponse response,
|
||||
boolean popup) throws IOException {
|
||||
response.sendRedirect(response.encodeRedirectURL(targetUrl));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.faces.ui;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.faces.component.UIComponent;
|
||||
import javax.faces.component.UIViewRoot;
|
||||
import javax.faces.component.behavior.ClientBehavior;
|
||||
import javax.faces.component.visit.VisitCallback;
|
||||
import javax.faces.component.visit.VisitContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.event.AbortProcessingException;
|
||||
import javax.faces.event.ComponentSystemEvent;
|
||||
import javax.faces.event.ComponentSystemEventListener;
|
||||
import javax.faces.event.PhaseId;
|
||||
import javax.faces.event.SystemEventListener;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A subclass of AjaxViewRoot for use with JSF 2.0.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note that these methods should ideally be in DelegatingViewRoot.java. However, due to some introspection done by the
|
||||
* JSF runtime that would make it impossible to use in JSF 1.2 because some of the delegate methods contain JSF 2.0
|
||||
* specific types and cause ClassNotFoundExceptions.
|
||||
* </p>
|
||||
*
|
||||
* @author Phil Webb
|
||||
*/
|
||||
public class Jsf2AjaxViewRoot extends AjaxViewRoot {
|
||||
|
||||
public Jsf2AjaxViewRoot(UIViewRoot original) {
|
||||
super(original);
|
||||
}
|
||||
|
||||
public void addClientBehavior(String eventName, ClientBehavior behavior) {
|
||||
getOriginalViewRoot().addClientBehavior(eventName, behavior);
|
||||
}
|
||||
|
||||
public void addComponentResource(FacesContext context, UIComponent componentResource) {
|
||||
getOriginalViewRoot().addComponentResource(context, componentResource);
|
||||
}
|
||||
|
||||
public void addComponentResource(FacesContext context, UIComponent componentResource, String target) {
|
||||
getOriginalViewRoot().addComponentResource(context, componentResource, target);
|
||||
}
|
||||
|
||||
public void broadcastEvents(FacesContext context, PhaseId phaseId) {
|
||||
getOriginalViewRoot().broadcastEvents(context, phaseId);
|
||||
}
|
||||
|
||||
public void clearInitialState() {
|
||||
getOriginalViewRoot().clearInitialState();
|
||||
}
|
||||
|
||||
public String createUniqueId(FacesContext context, String seed) {
|
||||
return getOriginalViewRoot().createUniqueId(context, seed);
|
||||
}
|
||||
|
||||
public Map getClientBehaviors() {
|
||||
return getOriginalViewRoot().getClientBehaviors();
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return getOriginalViewRoot().getClientId();
|
||||
}
|
||||
|
||||
public List getComponentResources(FacesContext context, String target) {
|
||||
return getOriginalViewRoot().getComponentResources(context, target);
|
||||
}
|
||||
|
||||
public String getDefaultEventName() {
|
||||
return getOriginalViewRoot().getDefaultEventName();
|
||||
}
|
||||
|
||||
public Collection getEventNames() {
|
||||
return getOriginalViewRoot().getEventNames();
|
||||
}
|
||||
|
||||
public List getListenersForEventClass(Class eventClass) {
|
||||
return getOriginalViewRoot().getListenersForEventClass(eventClass);
|
||||
}
|
||||
|
||||
public UIComponent getNamingContainer() {
|
||||
return getOriginalViewRoot().getNamingContainer();
|
||||
}
|
||||
|
||||
public List getPhaseListeners() {
|
||||
return getOriginalViewRoot().getPhaseListeners();
|
||||
}
|
||||
|
||||
public Map getResourceBundleMap() {
|
||||
return getOriginalViewRoot().getResourceBundleMap();
|
||||
}
|
||||
|
||||
public List getViewListenersForEventClass(Class systemEvent) {
|
||||
return getOriginalViewRoot().getViewListenersForEventClass(systemEvent);
|
||||
}
|
||||
|
||||
public Map getViewMap() {
|
||||
return getOriginalViewRoot().getViewMap();
|
||||
}
|
||||
|
||||
public Map getViewMap(boolean create) {
|
||||
return getOriginalViewRoot().getViewMap(create);
|
||||
}
|
||||
|
||||
public boolean initialStateMarked() {
|
||||
return getOriginalViewRoot().initialStateMarked();
|
||||
}
|
||||
|
||||
public void markInitialState() {
|
||||
getOriginalViewRoot().markInitialState();
|
||||
}
|
||||
|
||||
public boolean isInView() {
|
||||
return getOriginalViewRoot().isInView();
|
||||
}
|
||||
|
||||
public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
|
||||
getOriginalViewRoot().processEvent(event);
|
||||
}
|
||||
|
||||
public void removeComponentResource(FacesContext context, UIComponent componentResource) {
|
||||
getOriginalViewRoot().removeComponentResource(context, componentResource);
|
||||
}
|
||||
|
||||
public void removeComponentResource(FacesContext context, UIComponent componentResource, String target) {
|
||||
getOriginalViewRoot().removeComponentResource(context, componentResource, target);
|
||||
}
|
||||
|
||||
public void setInView(boolean isInView) {
|
||||
getOriginalViewRoot().setInView(isInView);
|
||||
}
|
||||
|
||||
public void subscribeToEvent(Class eventClass, ComponentSystemEventListener componentListener) {
|
||||
getOriginalViewRoot().subscribeToEvent(eventClass, componentListener);
|
||||
}
|
||||
|
||||
public void subscribeToViewEvent(Class systemEvent, SystemEventListener listener) {
|
||||
getOriginalViewRoot().subscribeToViewEvent(systemEvent, listener);
|
||||
}
|
||||
|
||||
public void unsubscribeFromEvent(Class eventClass, ComponentSystemEventListener componentListener) {
|
||||
getOriginalViewRoot().unsubscribeFromEvent(eventClass, componentListener);
|
||||
}
|
||||
|
||||
public void unsubscribeFromViewEvent(Class systemEvent, SystemEventListener listener) {
|
||||
getOriginalViewRoot().unsubscribeFromViewEvent(systemEvent, listener);
|
||||
}
|
||||
|
||||
public boolean visitTree(VisitContext context, VisitCallback callback) {
|
||||
return getOriginalViewRoot().visitTree(context, callback);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2004-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.faces.webflow;
|
||||
|
||||
import javax.faces.FactoryFinder;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.FacesContextFactory;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Provides helper methods for getting a FacesContext that is suitable for use outside of Web Flow. Inside a running
|
||||
* Flow session {@link FlowFacesContext} is typically used instead.
|
||||
* <p>
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class FacesContextHelper {
|
||||
|
||||
private boolean release = false;
|
||||
|
||||
public FacesContext getFacesContext(ServletContext servletContext, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
FacesContext facesContext = null;
|
||||
if (FacesContext.getCurrentInstance() != null) {
|
||||
facesContext = FacesContext.getCurrentInstance();
|
||||
} else {
|
||||
FacesContextFactory factory = (FacesContextFactory) FactoryFinder
|
||||
.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
|
||||
facesContext = factory.getFacesContext(servletContext, request, response, FlowLifecycle.newInstance());
|
||||
release = true;
|
||||
}
|
||||
return facesContext;
|
||||
}
|
||||
|
||||
public void releaseIfNecessary() {
|
||||
if (release) {
|
||||
FacesContext.getCurrentInstance().release();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,12 +17,8 @@ package org.springframework.faces.webflow;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.faces.FactoryFinder;
|
||||
import javax.faces.application.ResourceHandler;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.FacesContextFactory;
|
||||
import javax.faces.lifecycle.Lifecycle;
|
||||
import javax.faces.lifecycle.LifecycleFactory;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -42,18 +38,14 @@ public class FacesJsfResourceRequestHandler extends WebApplicationObjectSupport
|
||||
|
||||
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException,
|
||||
IOException {
|
||||
FacesContext context = getFacesContext(request, response);
|
||||
ResourceHandler resourceHandler = context.getApplication().getResourceHandler();
|
||||
resourceHandler.handleResourceRequest(context);
|
||||
}
|
||||
|
||||
private FacesContext getFacesContext(HttpServletRequest request, HttpServletResponse response) {
|
||||
FacesContextFactory facesContextFactory = (FacesContextFactory) FactoryFinder
|
||||
.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
|
||||
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
|
||||
.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
|
||||
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
|
||||
return facesContextFactory.getFacesContext(getServletContext(), request, response, lifecycle);
|
||||
FacesContextHelper helper = new FacesContextHelper();
|
||||
try {
|
||||
FacesContext facesContext = helper.getFacesContext(getServletContext(), request, response);
|
||||
ResourceHandler resourceHandler = facesContext.getApplication().getResourceHandler();
|
||||
resourceHandler.handleResourceRequest(facesContext);
|
||||
} finally {
|
||||
helper.releaseIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -81,16 +81,16 @@ public class FlowFacesContext extends FacesContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a FacesMessage to an SWF Message and adds it to the current MessageContext
|
||||
* Translates a FacesMessage to a Spring Web Flow message and adds it to the current MessageContext
|
||||
*/
|
||||
public void addMessage(String clientId, FacesMessage message) {
|
||||
messageDelegate.addMessage(clientId, message);
|
||||
messageDelegate.addToFlowMessageContext(clientId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator for all component clientId's for which messages have been added.
|
||||
*/
|
||||
public Iterator getClientIdsWithMessages() {
|
||||
public Iterator<String> getClientIdsWithMessages() {
|
||||
return messageDelegate.getClientIdsWithMessages();
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public class FlowFacesContext extends FacesContext {
|
||||
/**
|
||||
* Returns an Iterator for all Messages in the current MessageContext that does translation to FacesMessages.
|
||||
*/
|
||||
public Iterator getMessages() {
|
||||
public Iterator<FacesMessage> getMessages() {
|
||||
return messageDelegate.getMessages();
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ public class FlowFacesContext extends FacesContext {
|
||||
* Returns an Iterator for all Messages with the given clientId in the current MessageContext that does translation
|
||||
* to FacesMessages.
|
||||
*/
|
||||
public Iterator getMessages(String clientId) {
|
||||
public Iterator<FacesMessage> getMessages(String clientId) {
|
||||
return messageDelegate.getMessages(clientId);
|
||||
}
|
||||
|
||||
@@ -200,6 +200,10 @@ public class FlowFacesContext extends FacesContext {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
protected FlowFacesContextMessageDelegate getMessageDelegate() {
|
||||
return messageDelegate;
|
||||
}
|
||||
|
||||
protected class FlowExternalContext extends ExternalContextWrapper {
|
||||
|
||||
private static final String CUSTOM_RESPONSE = "customResponse";
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -63,7 +64,7 @@ public class FlowFacesContextMessageDelegate {
|
||||
/**
|
||||
* @see FlowFacesContext#addMessage(String, FacesMessage)
|
||||
*/
|
||||
public void addMessage(String clientId, FacesMessage message) {
|
||||
public void addToFlowMessageContext(String clientId, FacesMessage message) {
|
||||
String source = null;
|
||||
if (StringUtils.hasText(clientId)) {
|
||||
source = clientId;
|
||||
@@ -75,7 +76,7 @@ public class FlowFacesContextMessageDelegate {
|
||||
/**
|
||||
* @see FlowFacesContext#getClientIdsWithMessages
|
||||
*/
|
||||
public Iterator getClientIdsWithMessages() {
|
||||
public Iterator<String> getClientIdsWithMessages() {
|
||||
return new ClientIdIterator();
|
||||
}
|
||||
|
||||
@@ -102,19 +103,61 @@ public class FlowFacesContextMessageDelegate {
|
||||
/**
|
||||
* @see FlowFacesContext#getMessages()
|
||||
*/
|
||||
public Iterator getMessages() {
|
||||
public Iterator<FacesMessage> getMessages() {
|
||||
return new FacesMessageIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see FlowFacesContext#getMessages(String)
|
||||
*/
|
||||
public Iterator getMessages(String clientId) {
|
||||
public Iterator<FacesMessage> getMessages(String clientId) {
|
||||
return new FacesMessageIterator(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Jsf2FlowFacesContext#getMessageList()
|
||||
*/
|
||||
public List<FacesMessage> getMessageList() {
|
||||
return getMessageList(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Jsf2FlowFacesContext#getMessageList(String)
|
||||
*/
|
||||
public List<FacesMessage> getMessageList(String clientId) {
|
||||
List<FacesMessage> messages = getFacesMessages(clientId);
|
||||
if (null == messages) {
|
||||
return Collections.unmodifiableList(Collections.<FacesMessage> emptyList());
|
||||
} else {
|
||||
return Collections.unmodifiableList(messages);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ Private helper methods ----------------------//
|
||||
|
||||
private List<FacesMessage> getFacesMessages() {
|
||||
return getFacesMessages(null);
|
||||
}
|
||||
|
||||
private List<FacesMessage> getFacesMessages(String clientId) {
|
||||
List<FacesMessage> translatedMessages = new ArrayList<FacesMessage>();
|
||||
|
||||
Message[] summaryMessages = context.getMessageContext().getMessagesByCriteria(
|
||||
new MatchBySuffixCriteria(clientId, SUMMARY_MESSAGE_KEY));
|
||||
Message[] detailMessages = context.getMessageContext().getMessagesByCriteria(
|
||||
new MatchBySuffixCriteria(clientId, DETAIL_MESSAGE_KEY));
|
||||
for (int i = 0; i < summaryMessages.length; i++) {
|
||||
translatedMessages.add(toFacesMessage(summaryMessages[i], detailMessages[i]));
|
||||
}
|
||||
|
||||
Message[] userMessages = context.getMessageContext().getMessagesByCriteria(new UserMessageCriteria(clientId));
|
||||
for (int z = 0; z < userMessages.length; z++) {
|
||||
translatedMessages.add(toFacesMessage(userMessages[z], userMessages[z]));
|
||||
}
|
||||
|
||||
return translatedMessages;
|
||||
}
|
||||
|
||||
private FacesMessage toFacesMessage(Message summaryMessage, Message detailMessage) {
|
||||
|
||||
// If we can return the actual message instance.
|
||||
@@ -137,49 +180,25 @@ public class FlowFacesContextMessageDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private class FacesMessageIterator implements Iterator {
|
||||
private class FacesMessageIterator implements Iterator<FacesMessage> {
|
||||
|
||||
private Object[] messages;
|
||||
private FacesMessage[] messages;
|
||||
|
||||
private int currentIndex = -1;
|
||||
|
||||
protected FacesMessageIterator() {
|
||||
Message[] summaryMessages = context.getMessageContext().getMessagesByCriteria(new SummaryMessageCriteria());
|
||||
Message[] detailMessages = context.getMessageContext().getMessagesByCriteria(new DetailMessageCriteria());
|
||||
Message[] userMessages = context.getMessageContext().getMessagesByCriteria(new UserMessageCriteria());
|
||||
|
||||
List translatedMessages = new ArrayList();
|
||||
for (int i = 0; i < summaryMessages.length; i++) {
|
||||
translatedMessages.add(toFacesMessage(summaryMessages[i], detailMessages[i]));
|
||||
}
|
||||
for (int z = 0; z < userMessages.length; z++) {
|
||||
translatedMessages.add(toFacesMessage(userMessages[z], userMessages[z]));
|
||||
}
|
||||
|
||||
this.messages = translatedMessages.toArray();
|
||||
this.messages = getFacesMessages().toArray(new FacesMessage[] {});
|
||||
}
|
||||
|
||||
protected FacesMessageIterator(String clientId) {
|
||||
Message[] summaryMessages = context.getMessageContext().getMessagesBySource(clientId + SUMMARY_MESSAGE_KEY);
|
||||
Message[] detailMessages = context.getMessageContext().getMessagesBySource(clientId + DETAIL_MESSAGE_KEY);
|
||||
Message[] userMessages = context.getMessageContext().getMessagesBySource(clientId);
|
||||
|
||||
List translatedMessages = new ArrayList();
|
||||
for (int i = 0; i < summaryMessages.length; i++) {
|
||||
translatedMessages.add(toFacesMessage(summaryMessages[i], detailMessages[i]));
|
||||
}
|
||||
for (int z = 0; z < userMessages.length; z++) {
|
||||
translatedMessages.add(toFacesMessage(userMessages[z], userMessages[z]));
|
||||
}
|
||||
|
||||
this.messages = translatedMessages.toArray();
|
||||
this.messages = getFacesMessages(clientId).toArray(new FacesMessage[] {});
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return messages.length > currentIndex + 1;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
public FacesMessage next() {
|
||||
currentIndex++;
|
||||
return messages[currentIndex];
|
||||
}
|
||||
@@ -190,7 +209,7 @@ public class FlowFacesContextMessageDelegate {
|
||||
|
||||
}
|
||||
|
||||
private class ClientIdIterator implements Iterator {
|
||||
private class ClientIdIterator implements Iterator<String> {
|
||||
|
||||
private Message[] messages;
|
||||
|
||||
@@ -204,7 +223,7 @@ public class FlowFacesContextMessageDelegate {
|
||||
return messages.length > currentIndex + 1;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
public String next() {
|
||||
Message next = messages[++currentIndex];
|
||||
if (next.getSource() == null) {
|
||||
return null;
|
||||
@@ -221,34 +240,46 @@ public class FlowFacesContextMessageDelegate {
|
||||
|
||||
}
|
||||
|
||||
private class SummaryMessageCriteria implements MessageCriteria {
|
||||
private class MatchBySuffixCriteria implements MessageCriteria {
|
||||
|
||||
public boolean test(Message message) {
|
||||
if (message.getSource() == null) {
|
||||
return false;
|
||||
}
|
||||
return message.getSource().toString().endsWith(SUMMARY_MESSAGE_KEY);
|
||||
private String clientId;
|
||||
private String suffix;
|
||||
|
||||
public MatchBySuffixCriteria(String clientId, String suffix) {
|
||||
this.clientId = clientId;
|
||||
this.suffix = suffix;
|
||||
}
|
||||
}
|
||||
|
||||
private class DetailMessageCriteria implements MessageCriteria {
|
||||
|
||||
public boolean test(Message message) {
|
||||
if (message.getSource() == null) {
|
||||
return false;
|
||||
boolean result = false;
|
||||
if (message.getSource() != null) {
|
||||
if (clientId != null) {
|
||||
result = message.getSource().toString().equals(clientId + suffix);
|
||||
} else {
|
||||
result = message.getSource().toString().endsWith(suffix);
|
||||
}
|
||||
}
|
||||
return message.getSource().toString().endsWith(DETAIL_MESSAGE_KEY);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private class UserMessageCriteria implements MessageCriteria {
|
||||
|
||||
private String clientId;
|
||||
|
||||
public UserMessageCriteria(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public boolean test(Message message) {
|
||||
if (message.getSource() == null) {
|
||||
return true;
|
||||
boolean result = false;
|
||||
if (clientId != null) {
|
||||
result = new MatchBySuffixCriteria(clientId, "").test(message);
|
||||
} else {
|
||||
result = (!new MatchBySuffixCriteria(clientId, SUMMARY_MESSAGE_KEY).test(message))
|
||||
&& (!new MatchBySuffixCriteria(clientId, DETAIL_MESSAGE_KEY).test(message));
|
||||
}
|
||||
return !message.getSource().toString().endsWith(SUMMARY_MESSAGE_KEY)
|
||||
&& !message.getSource().toString().endsWith(DETAIL_MESSAGE_KEY);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +287,7 @@ public class FlowFacesContextMessageDelegate {
|
||||
|
||||
String nullSummaryId = null + SUMMARY_MESSAGE_KEY;
|
||||
|
||||
private Set identifiedMessageSources = new HashSet();
|
||||
private Set<String> identifiedMessageSources = new HashSet<String>();
|
||||
|
||||
// From getClientIdsWithMessages docs: If any messages have been queued that were not associated with
|
||||
// any specific client identifier, a null value will be included in the iterated values.
|
||||
@@ -267,7 +298,7 @@ public class FlowFacesContextMessageDelegate {
|
||||
|| message.getSource().equals(nullSummaryId)) {
|
||||
return identifiedMessageSources.add(null);
|
||||
}
|
||||
return identifiedMessageSources.add(message.getSource());
|
||||
return identifiedMessageSources.add((String) message.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@ public class FlowSerializedView implements Serializable {
|
||||
return this.componentState;
|
||||
}
|
||||
|
||||
public Object[] asTreeStructAndCompStateArray() {
|
||||
return new Object[] { this.treeStructure, this.componentState };
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("viewId", viewId).toString();
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ public class FlowViewStateManager extends StateManager {
|
||||
delegate.writeState(context, state); // MyFaces
|
||||
} else if (state instanceof FlowSerializedView) { // Mojarra
|
||||
FlowSerializedView view = (FlowSerializedView) state;
|
||||
delegate.writeState(context, new Object[] { view.getTreeStructure(), view.getComponentState() });
|
||||
delegate.writeState(context, view.asTreeStructAndCompStateArray());
|
||||
} else {
|
||||
super.writeState(context, state);
|
||||
}
|
||||
@@ -173,4 +173,22 @@ public class FlowViewStateManager extends StateManager {
|
||||
return viewRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getViewState(FacesContext context) {
|
||||
/*
|
||||
* Mojarra 2: PartialRequestContextImpl.renderState() invokes this method during Ajax request rendering. It is
|
||||
* overridden to convert FlowSerializedView to an array containing tree structure and component state. The
|
||||
* ResponseStateManager.getViewState() calls the ServerSideStateHelper, which expects the array.
|
||||
*/
|
||||
Object state = saveView(context);
|
||||
if (state != null) {
|
||||
if (state instanceof FlowSerializedView) {
|
||||
FlowSerializedView view = (FlowSerializedView) state;
|
||||
state = view.asTreeStructAndCompStateArray();
|
||||
}
|
||||
return context.getRenderKit().getResponseStateManager().getViewState(context, state);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.io.Writer;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.faces.FactoryFinder;
|
||||
import javax.faces.application.FacesMessage;
|
||||
import javax.faces.application.ProjectStage;
|
||||
import javax.faces.context.ExceptionHandler;
|
||||
@@ -28,20 +29,32 @@ import javax.faces.context.ExternalContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.Flash;
|
||||
import javax.faces.context.PartialViewContext;
|
||||
import javax.faces.context.PartialViewContextFactory;
|
||||
import javax.faces.event.PhaseId;
|
||||
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Extends FlowFacesContext in order to provide JSF 2 delegation method. This is necessary because some of the methods
|
||||
* use JSF 2 specific types as input or output parameters.
|
||||
* Extends FlowFacesContext in order to provide JSF 2 delegation method.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class Jsf2FlowFacesContext extends FlowFacesContext {
|
||||
|
||||
/*
|
||||
* This partialViewContext duplicates the one FacesContextImpl because the constructor of FacesContextImpl calls
|
||||
* getPartialViewContext(), which causes it to be instantiated with an instance of FacesContextImpl. This leads to
|
||||
* issues with adding and showing validation messages during Ajax requests because the FlowFacesContext is
|
||||
* effectively bypassed.
|
||||
*/
|
||||
private PartialViewContext partialViewContext;
|
||||
|
||||
public Jsf2FlowFacesContext(RequestContext context, FacesContext delegate) {
|
||||
super(context, delegate);
|
||||
|
||||
PartialViewContextFactory f = (PartialViewContextFactory) FactoryFinder
|
||||
.getFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY);
|
||||
partialViewContext = f.getPartialViewContext(this);
|
||||
}
|
||||
|
||||
public ExternalContext getExternalContext() {
|
||||
@@ -55,15 +68,22 @@ public class Jsf2FlowFacesContext extends FlowFacesContext {
|
||||
}
|
||||
|
||||
public PartialViewContext getPartialViewContext() {
|
||||
return getDelegate().getPartialViewContext();
|
||||
return partialViewContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a List for all Messages in the current MessageContext that does translation to FacesMessages.
|
||||
*/
|
||||
public List<FacesMessage> getMessageList() {
|
||||
return getDelegate().getMessageList();
|
||||
return getMessageDelegate().getMessageList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a List for all Messages with the given clientId in the current MessageContext that does translation to
|
||||
* FacesMessages.
|
||||
*/
|
||||
public List<FacesMessage> getMessageList(String clientId) {
|
||||
return getDelegate().getMessageList(clientId);
|
||||
return getMessageDelegate().getMessageList(clientId);
|
||||
}
|
||||
|
||||
public boolean isPostback() {
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2004-2010 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.faces.webflow;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.faces.FactoryFinder;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.context.FacesContextWrapper;
|
||||
import javax.faces.context.PartialResponseWriter;
|
||||
import javax.faces.render.RenderKit;
|
||||
import javax.faces.render.RenderKitFactory;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.js.ajax.AbstractAjaxHandler;
|
||||
|
||||
import com.sun.faces.context.PartialViewContextImpl;
|
||||
|
||||
/**
|
||||
* Ajax handler for JSF 2 requests that can identify JSF 2 Ajax requests and send redirect instructions back to the
|
||||
* client by including a redirect instruction in the content of the response.
|
||||
*
|
||||
* @see AbstractAjaxHandler
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class JsfAjaxHandler extends AbstractAjaxHandler {
|
||||
|
||||
public JsfAjaxHandler() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public JsfAjaxHandler(AbstractAjaxHandler delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
protected boolean isAjaxRequestInternal(HttpServletRequest request, HttpServletResponse response) {
|
||||
String facesRequestHeader = request.getHeader("Faces-Request");
|
||||
return ("partial/ajax".equals(facesRequestHeader)) ? true : false;
|
||||
}
|
||||
|
||||
protected void sendAjaxRedirectInternal(final String targetUrl, final HttpServletRequest request,
|
||||
final HttpServletResponse response, boolean popup) throws IOException {
|
||||
|
||||
// Ideally facesContext.getExternalContext().redirect() should be used instead of the code in this method.
|
||||
// However PartialViewContextImpl.createPartialResponseWriter() calls cxt.getRenderKit(), which in turn
|
||||
// tries to get the UIViewRoot's renderKitId. That results in NPE when JsfAjaxHandler is called
|
||||
// outside of flow execution. The code below wraps the FacesContext to override getRenderKit() and provide a
|
||||
// default render kit id.
|
||||
|
||||
FacesContextHelper helper = new FacesContextHelper();
|
||||
try {
|
||||
FacesContext facesContext = helper.getFacesContext(getServletContext(), request, response);
|
||||
facesContext = new FixedRenderKitFacesContext(facesContext, determineRenderKitId(request, response));
|
||||
PartialViewContextImpl partialViewContext = new PartialViewContextImpl(facesContext);
|
||||
PartialResponseWriter writer = partialViewContext.getPartialResponseWriter();
|
||||
writer.startDocument();
|
||||
writer.redirect(targetUrl);
|
||||
writer.endDocument();
|
||||
} finally {
|
||||
helper.releaseIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
protected String determineRenderKitId(HttpServletRequest request, HttpServletResponse response) {
|
||||
return RenderKitFactory.HTML_BASIC_RENDER_KIT;
|
||||
}
|
||||
|
||||
private class FixedRenderKitFacesContext extends FacesContextWrapper {
|
||||
|
||||
private FacesContext delegate;
|
||||
private String renderKitId;
|
||||
|
||||
public FixedRenderKitFacesContext(FacesContext delegate, String renderKitId) {
|
||||
this.delegate = delegate;
|
||||
this.renderKitId = renderKitId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FacesContext getWrapped() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderKit getRenderKit() {
|
||||
RenderKitFactory factory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
|
||||
return factory.getRenderKit(this, renderKitId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,6 +59,10 @@ public class JsfRuntimeInformation {
|
||||
return jsfVersion >= JSF_12;
|
||||
}
|
||||
|
||||
public static boolean isLessThanJsf20() {
|
||||
return jsfVersion < JSF_20;
|
||||
}
|
||||
|
||||
protected static boolean isMyFacesPresent() {
|
||||
return myFacesPresent;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.faces.webflow;
|
||||
|
||||
import static org.springframework.faces.webflow.JsfRuntimeInformation.isAtLeastJsf12;
|
||||
import static org.springframework.faces.webflow.JsfRuntimeInformation.isAtLeastJsf20;
|
||||
import static org.springframework.faces.webflow.JsfRuntimeInformation.isLessThanJsf20;
|
||||
import static org.springframework.faces.webflow.JsfRuntimeInformation.isPortletRequest;
|
||||
|
||||
import java.util.Iterator;
|
||||
@@ -37,7 +38,6 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.faces.ui.AjaxViewRoot;
|
||||
import org.springframework.faces.ui.Jsf2AjaxViewRoot;
|
||||
import org.springframework.js.ajax.SpringJavascriptAjaxHandler;
|
||||
import org.springframework.webflow.context.ExternalContext;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
@@ -143,12 +143,10 @@ public class JsfViewFactory implements ViewFactory {
|
||||
}
|
||||
|
||||
private JsfView createJsfView(UIViewRoot root, Lifecycle lifecycle, RequestContext context) {
|
||||
if (isSpringJavascriptAjaxRequest(context.getExternalContext())) {
|
||||
AjaxViewRoot viewRoot = (isAtLeastJsf20()) ? new Jsf2AjaxViewRoot(root) : new AjaxViewRoot(root);
|
||||
return new JsfView(viewRoot, lifecycle, context);
|
||||
} else {
|
||||
return new JsfView(root, lifecycle, context);
|
||||
if (isLessThanJsf20() && isSpringJavascriptAjaxRequest(context.getExternalContext())) {
|
||||
root = new AjaxViewRoot(root);
|
||||
}
|
||||
return new JsfView(root, lifecycle, context);
|
||||
}
|
||||
|
||||
private boolean isSpringJavascriptAjaxRequest(ExternalContext context) {
|
||||
|
||||
@@ -153,12 +153,8 @@ public class FlowFacesContextTests extends TestCase {
|
||||
EasyMock.expect(requestContext.getMessageContext()).andStubReturn(messageContext);
|
||||
EasyMock.replay(new Object[] { requestContext });
|
||||
|
||||
int iterationCount = 0;
|
||||
Iterator i = facesContext.getMessages("unknown");
|
||||
while (i.hasNext()) {
|
||||
iterationCount++;
|
||||
}
|
||||
assertEquals(0, iterationCount);
|
||||
assertFalse(i.hasNext());
|
||||
}
|
||||
|
||||
public final void testGetClientIdsWithMessages() {
|
||||
|
||||
@@ -127,7 +127,6 @@ public class JSFMockHelper {
|
||||
FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, MockRenderKitFactory.class.getName());
|
||||
FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY, MockPartialViewContextFactory.class
|
||||
.getName());
|
||||
externalContext = new MockExternalContext(servletContext, request, response);
|
||||
lifecycleFactory = (MockLifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
|
||||
lifecycle = (MockLifecycle) lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
|
||||
facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springframework.faces.webflow;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.myfaces.test.mock.MockPrintWriter;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
|
||||
public class JsfAjaxHandlerTests extends TestCase {
|
||||
|
||||
private JSFMockHelper jsfMock = new JSFMockHelper();
|
||||
private JsfAjaxHandler ajaxHandler;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
jsfMock.setUp();
|
||||
StaticWebApplicationContext webappContext = new StaticWebApplicationContext();
|
||||
webappContext.setServletContext(jsfMock.servletContext());
|
||||
ajaxHandler = new JsfAjaxHandler();
|
||||
ajaxHandler.setApplicationContext(webappContext);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
jsfMock.tearDown();
|
||||
}
|
||||
|
||||
public void testSendAjaxRedirect() throws Exception {
|
||||
ajaxHandler.sendAjaxRedirectInternal("/target", jsfMock.request(), jsfMock.response(), false);
|
||||
assertEquals(
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<partial-response><redirect url=\"/target\"/></partial-response>",
|
||||
extractResponseContent());
|
||||
}
|
||||
|
||||
private String extractResponseContent() throws IOException {
|
||||
MockPrintWriter writer = (MockPrintWriter) jsfMock.response().getWriter();
|
||||
return new String(writer.content());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import org.easymock.EasyMock;
|
||||
import org.jboss.el.ExpressionFactoryImpl;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.support.FluentParserContext;
|
||||
import org.springframework.faces.ui.AjaxViewRoot;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
@@ -218,7 +217,7 @@ public class JsfViewFactoryTests extends TestCase {
|
||||
|
||||
assertNotNull("A View was not restored", restoredView);
|
||||
assertTrue("A JsfView was expected", restoredView instanceof JsfView);
|
||||
assertTrue("An AjaxViewRoot was not set", ((JsfView) restoredView).getViewRoot() instanceof AjaxViewRoot);
|
||||
assertTrue("An ViewRoot was not set", ((JsfView) restoredView).getViewRoot() instanceof UIViewRoot);
|
||||
assertEquals("View name did not match", VIEW_ID, ((JsfView) restoredView).getViewRoot().getViewId());
|
||||
assertFalse("An unexpected event was signaled,", restoredView.hasFlowEvent());
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.myfaces.test.mock.MockExternalContext;
|
||||
import org.apache.myfaces.test.mock.MockExternalContext20;
|
||||
|
||||
public class MockBaseFacesContextFactory extends FacesContextFactory {
|
||||
|
||||
@@ -21,7 +21,7 @@ public class MockBaseFacesContextFactory extends FacesContextFactory {
|
||||
return FacesContext.getCurrentInstance();
|
||||
} else {
|
||||
|
||||
ExternalContext ext = new MockExternalContext((ServletContext) context, (HttpServletRequest) request,
|
||||
ExternalContext ext = new MockExternalContext20((ServletContext) context, (HttpServletRequest) request,
|
||||
(HttpServletResponse) response);
|
||||
|
||||
return new MockBaseFacesContext(ext, lifecycle);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.springframework.js.ajax;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.context.support.WebApplicationObjectSupport;
|
||||
|
||||
public abstract class AbstractAjaxHandler extends WebApplicationObjectSupport implements AjaxHandler {
|
||||
|
||||
private AbstractAjaxHandler delegate;
|
||||
|
||||
public AbstractAjaxHandler(AbstractAjaxHandler delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public final boolean isAjaxRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (isAjaxRequestInternal(request, response)) {
|
||||
return true;
|
||||
}
|
||||
if (delegate != null) {
|
||||
return delegate.isAjaxRequest(request, response);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final void sendAjaxRedirect(String targetUrl, HttpServletRequest request, HttpServletResponse response,
|
||||
boolean popup) throws IOException {
|
||||
if (isAjaxRequestInternal(request, response)) {
|
||||
sendAjaxRedirectInternal(targetUrl, request, response, popup);
|
||||
}
|
||||
if (delegate != null) {
|
||||
delegate.sendAjaxRedirect(targetUrl, request, response, popup);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean isAjaxRequestInternal(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
protected abstract void sendAjaxRedirectInternal(String targetUrl, HttpServletRequest request,
|
||||
HttpServletResponse response, boolean popup) throws IOException;
|
||||
|
||||
}
|
||||
@@ -25,10 +25,12 @@ import org.springframework.util.StringUtils;
|
||||
/**
|
||||
* Ajax handler for Spring Javascript (Spring.js).
|
||||
*
|
||||
* @see AbstractAjaxHandler
|
||||
*
|
||||
* @author Jeremy Grelle
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class SpringJavascriptAjaxHandler implements AjaxHandler {
|
||||
public class SpringJavascriptAjaxHandler extends AbstractAjaxHandler {
|
||||
|
||||
/**
|
||||
* The response header to be set on an Ajax redirect
|
||||
@@ -50,7 +52,21 @@ public class SpringJavascriptAjaxHandler implements AjaxHandler {
|
||||
*/
|
||||
public static final String AJAX_SOURCE_PARAM = "ajaxSource";
|
||||
|
||||
public boolean isAjaxRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
/**
|
||||
* Create a SpringJavascriptAjaxHandler that is not part of a chain of AjaxHandler's.
|
||||
*/
|
||||
public SpringJavascriptAjaxHandler() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SpringJavascriptAjaxHandler as part of a chain of AjaxHandler's.
|
||||
*/
|
||||
public SpringJavascriptAjaxHandler(AbstractAjaxHandler delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
protected boolean isAjaxRequestInternal(HttpServletRequest request, HttpServletResponse response) {
|
||||
String acceptHeader = request.getHeader("Accept");
|
||||
String ajaxParam = request.getParameter(AJAX_SOURCE_PARAM);
|
||||
if (AJAX_ACCEPT_CONTENT_TYPE.equals(acceptHeader) || StringUtils.hasText(ajaxParam)) {
|
||||
@@ -60,7 +76,7 @@ public class SpringJavascriptAjaxHandler implements AjaxHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public void sendAjaxRedirect(String targetUrl, HttpServletRequest request, HttpServletResponse response,
|
||||
protected void sendAjaxRedirectInternal(String targetUrl, HttpServletRequest request, HttpServletResponse response,
|
||||
boolean popup) throws IOException {
|
||||
if (popup) {
|
||||
response.setHeader(POPUP_VIEW_HEADER, "true");
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package org.springframework.js.ajax;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
public class AbstractAjaxHandlerTests extends TestCase {
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
}
|
||||
|
||||
public void testIsAjaxRequest() throws Exception {
|
||||
TestAjaxHandler handler = new TestAjaxHandler(null, true);
|
||||
assertTrue(handler.isAjaxRequest(request, response));
|
||||
}
|
||||
|
||||
public void testIsNotAjaxRequest() throws Exception {
|
||||
TestAjaxHandler handler = new TestAjaxHandler(null, false);
|
||||
assertFalse(handler.isAjaxRequest(request, response));
|
||||
}
|
||||
|
||||
public void testIsAjaxRequestViaDelegate() throws Exception {
|
||||
TestAjaxHandler handler = new TestAjaxHandler(new TestAjaxHandler(null, true), false);
|
||||
assertTrue(handler.isAjaxRequest(request, response));
|
||||
}
|
||||
|
||||
public void testSendAjaxRedirect() throws Exception {
|
||||
TestAjaxHandler handler = new TestAjaxHandler(null, true);
|
||||
handler.sendAjaxRedirect("", request, response, false);
|
||||
assertTrue(handler.wasAjaxRedirectInternalCalled);
|
||||
}
|
||||
|
||||
public void testAjaxRedirectNotSent() throws Exception {
|
||||
TestAjaxHandler handler = new TestAjaxHandler(null, false);
|
||||
handler.sendAjaxRedirect("", request, response, false);
|
||||
assertFalse(handler.wasAjaxRedirectInternalCalled());
|
||||
}
|
||||
|
||||
public void testSendAjaxRedirectViaDelegate() throws Exception {
|
||||
TestAjaxHandler handler = new TestAjaxHandler(new TestAjaxHandler(null, true), false);
|
||||
handler.sendAjaxRedirect("", request, response, false);
|
||||
assertTrue(handler.wasAjaxRedirectInternalCalled());
|
||||
}
|
||||
|
||||
private final class TestAjaxHandler extends AbstractAjaxHandler {
|
||||
|
||||
private boolean isAjaxRequest;
|
||||
private boolean wasAjaxRedirectInternalCalled;
|
||||
private TestAjaxHandler delegate;
|
||||
|
||||
private TestAjaxHandler(TestAjaxHandler delegate, boolean isAjaxRequest) {
|
||||
super(delegate);
|
||||
this.delegate = delegate;
|
||||
this.isAjaxRequest = isAjaxRequest;
|
||||
}
|
||||
|
||||
protected boolean isAjaxRequestInternal(HttpServletRequest request, HttpServletResponse response) {
|
||||
return isAjaxRequest;
|
||||
}
|
||||
|
||||
protected void sendAjaxRedirectInternal(String targetUrl, HttpServletRequest request,
|
||||
HttpServletResponse response, boolean popup) throws IOException {
|
||||
wasAjaxRedirectInternalCalled = true;
|
||||
}
|
||||
|
||||
public TestAjaxHandler getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
public boolean wasAjaxRedirectInternalCalled() {
|
||||
if (wasAjaxRedirectInternalCalled) {
|
||||
return true;
|
||||
} else {
|
||||
return (getDelegate() != null) ? delegate.wasAjaxRedirectInternalCalled() : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,7 @@ public class ResourceServletTests extends TestCase {
|
||||
|
||||
public final void testExecute() throws Exception {
|
||||
|
||||
String requestPath = "/dojo/dojo.js";
|
||||
String requestPath = "/spring/Spring.js";
|
||||
request.setPathInfo(requestPath);
|
||||
servlet.doGet(request, response);
|
||||
|
||||
@@ -41,10 +41,10 @@ public class ResourceServletTests extends TestCase {
|
||||
|
||||
public final void testExecute_CombinedResources() throws Exception {
|
||||
|
||||
String requestPath = "/dojo/dojo.js";
|
||||
String requestPath = "/spring/Spring.js";
|
||||
request.setPathInfo(requestPath);
|
||||
Map params = new HashMap();
|
||||
params.put("appended", "/dijit/dijit.js,/dijit/Dialog.js");
|
||||
params.put("appended", "/spring/Spring-Dojo.js");
|
||||
request.setParameters(params);
|
||||
servlet.doGet(request, response);
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ResourceServletTests extends TestCase {
|
||||
|
||||
public final void testExecute_CompressedResponse() throws Exception {
|
||||
|
||||
String requestPath = "/dojo/dojo.js";
|
||||
String requestPath = "/spring/Spring.js";
|
||||
request.setPathInfo(requestPath);
|
||||
request.addHeader("Accept-Encoding", "gzip");
|
||||
servlet.doGet(request, response);
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
#Sun Apr 27 09:05:45 EDT 2008
|
||||
#Wed Jul 28 13:06:21 BST 2010
|
||||
eclipse.preferences.version=1
|
||||
instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
|
||||
org.springframework.ide.eclipse.core.builders.enable.aopreferencemodelbuilder=true
|
||||
org.springframework.ide.eclipse.core.builders.enable.beanmetadatabuilder=true
|
||||
org.springframework.ide.eclipse.core.builders.enable.osgibundleupdater=true
|
||||
org.springframework.ide.eclipse.core.enable.project.preferences=true
|
||||
org.springframework.ide.eclipse.core.validator.enable.com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.bestpractices.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.core.springvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.applicationSymbolicNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.applicationVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleActivationPolicyRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleActivatorRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleManifestVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleSymbolicNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.exportPackageRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.importRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.parsingProblemsRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.requireBundleRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.AvoidDriverManagerDataSource-com.springsource.sts.bestpractices.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.ImportElementsAtTopRulee-com.springsource.sts.bestpractices.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.ParentBeanSpecifiesAbstractClassRule-com.springsource.sts.bestpractices.beansvalidator=true
|
||||
@@ -16,6 +30,11 @@ org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.UnnecessaryValueElementRule-com.springsource.sts.bestpractices.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.UseBeanInheritance-com.springsource.sts.bestpractices.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.legacyxmlusage.jndiobjectfactory-com.springsource.sts.bestpractices.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importBundleVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importLibraryVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importPackageVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.requireBundleVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.autowire.autowire-org.springframework.ide.eclipse.beans.core.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanAlias-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanClass-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanConstructorArgument-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
@@ -28,6 +47,7 @@ org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.i
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.methodOverride-org.springframework.ide.eclipse.beans.core.beansvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.parsingProblems-org.springframework.ide.eclipse.beans.core.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.requiredProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.toolAnnotation-org.springframework.ide.eclipse.beans.core.beansvalidator=false
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.core.springClasspath-org.springframework.ide.eclipse.core.springvalidator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.action-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.actionstate-org.springframework.ide.eclipse.webflow.core.validator=true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<webflow-project-description>
|
||||
<version>1</version>
|
||||
<pluginVersion><![CDATA[2.2.1.v200811281800]]></pluginVersion>
|
||||
<pluginVersion><![CDATA[2.3.3.201005082200-CI-R3771-B737]]></pluginVersion>
|
||||
<configs>
|
||||
<config>
|
||||
<file>src/main/webapp/WEB-INF/flows/booking/booking-flow.xml</file>
|
||||
@@ -10,8 +10,7 @@
|
||||
</config>
|
||||
<config>
|
||||
<file>src/main/webapp/WEB-INF/flows/main/main-flow.xml</file>
|
||||
<name><![CDATA[main]]></name>
|
||||
<beans-config><![CDATA[1:BeansModel|2:swf-booking-faces|3:src/main/webapp/WEB-INF/config/web-application-config.xml]]></beans-config>
|
||||
<name><![CDATA[main-flow]]></name>
|
||||
</config>
|
||||
</configs>
|
||||
</webflow-project-description>
|
||||
|
||||
@@ -30,8 +30,10 @@
|
||||
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.2.6.ga" conf="compile->runtime"/>
|
||||
<dependency org="org.hibernate" name="com.springsource.org.hibernate.annotations" rev="3.3.0.ga" conf="compile->runtime"/>
|
||||
<dependency org="org.hibernate" name="com.springsource.org.hibernate.ejb" rev="3.3.1.ga" conf="compile->runtime"/>
|
||||
<dependency org="org.hibernate" name="com.springsource.org.hibernate.validator" rev="4.1.0.GA" />
|
||||
<dependency org="org.hsqldb" name="com.springsource.org.hsqldb" rev="1.8.0.9" conf="compile->runtime"/>
|
||||
<dependency org="org.joda" name="com.springsource.org.joda.time" rev="1.6.0" conf="compile->runtime"/>
|
||||
<dependency org="org.slf4j" name="com.springsource.slf4j.log4j" rev="1.5.6" />
|
||||
<dependency org="org.springframework" name="org.springframework.aop" rev="3.0.3.RELEASE" conf="compile->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.beans" rev="3.0.3.RELEASE" conf="compile->runtime"/>
|
||||
<dependency org="org.springframework" name="org.springframework.context" rev="3.0.3.RELEASE" conf="compile->runtime"/>
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
<artifactId>com.springsource.org.hibernate.ejb</artifactId>
|
||||
<version>3.3.1.ga</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>com.springsource.org.hibernate.validator</artifactId>
|
||||
<version>4.1.0.GA</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>com.springsource.org.hsqldb</artifactId>
|
||||
@@ -52,6 +57,11 @@
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>1.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>com.springsource.slf4j.log4j</artifactId>
|
||||
<version>1.5.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.aop</artifactId>
|
||||
|
||||
@@ -15,6 +15,9 @@ import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.springframework.binding.message.MessageBuilder;
|
||||
import org.springframework.binding.message.MessageContext;
|
||||
@@ -34,12 +37,17 @@ public class Booking implements Serializable {
|
||||
|
||||
private Hotel hotel;
|
||||
|
||||
@NotNull
|
||||
private Date checkinDate;
|
||||
|
||||
@NotNull
|
||||
private Date checkoutDate;
|
||||
|
||||
@Pattern(regexp = "[0-9]{16}", message = "Credit card number must be 16 digits.")
|
||||
private String creditCard;
|
||||
|
||||
@NotNull
|
||||
@Size(min = 3, message = "A valid credit card name is required.")
|
||||
private String creditCardName;
|
||||
|
||||
private int creditCardExpiryMonth;
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
<!-- Dispatches requests mapped to flows to FlowHandler implementations -->
|
||||
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
|
||||
<property name="flowExecutor" ref="flowExecutor" />
|
||||
<property name="ajaxHandler">
|
||||
<bean class="org.springframework.faces.webflow.JsfAjaxHandler"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Dispatches requests mapped to org.springframework.web.HttpRequestHandler implementations -->
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
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="span-5">
|
||||
<h3>${booking.hotel.name}</h3>
|
||||
<address>
|
||||
@@ -18,12 +16,8 @@
|
||||
${booking.hotel.country}
|
||||
</address>
|
||||
</div>
|
||||
<div class="span-12">
|
||||
<ui:fragment id="messages">
|
||||
<div id="messagesInsertionPoint">
|
||||
<h:messages errorClass="error" layout="table"/>
|
||||
</div>
|
||||
</ui:fragment>
|
||||
<h:panelGroup id="bookingsFragment" styleClass="span-12" layout="block">
|
||||
<h:messages errorClass="error" layout="table"/>
|
||||
<h:form id="bookingForm">
|
||||
<fieldset>
|
||||
<legend>Book Hotel</legend>
|
||||
@@ -45,11 +39,9 @@
|
||||
</div>
|
||||
<div class="span-7 last">
|
||||
<p>
|
||||
<sf:clientDateValidator required="true">
|
||||
<h:inputText id="checkinDate" value="#{booking.checkinDate}" required="true">
|
||||
<f:convertDateTime pattern="MM-dd-yyyy" timeZone="EST"/>
|
||||
</h:inputText>
|
||||
</sf:clientDateValidator>
|
||||
<h:inputText id="checkinDate" value="#{booking.checkinDate}" required="true">
|
||||
<f:convertDateTime pattern="MM-dd-yyyy" timeZone="EST"/>
|
||||
</h:inputText>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -59,11 +51,9 @@
|
||||
</div>
|
||||
<div class="span-7 last">
|
||||
<p>
|
||||
<sf:clientDateValidator required="true">
|
||||
<h:inputText id="checkoutDate" value="#{booking.checkoutDate}" required="true">
|
||||
<f:convertDateTime pattern="MM-dd-yyyy" timeZone="EST"/>
|
||||
</h:inputText>
|
||||
</sf:clientDateValidator>
|
||||
<h:inputText id="checkoutDate" value="#{booking.checkoutDate}" required="true">
|
||||
<f:convertDateTime pattern="MM-dd-yyyy" timeZone="EST"/>
|
||||
</h:inputText>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,9 +106,7 @@
|
||||
</div>
|
||||
<div class="span-7 last">
|
||||
<p>
|
||||
<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>
|
||||
<h:inputText id="creditCard" value="#{booking.creditCard}"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -128,9 +116,7 @@
|
||||
</div>
|
||||
<div class="span-7 last">
|
||||
<p>
|
||||
<sf:clientTextValidator required="true">
|
||||
<h:inputText id="creditCardName" value="#{booking.creditCardName}" required="true"/>
|
||||
</sf:clientTextValidator>
|
||||
<h:inputText id="creditCardName" value="#{booking.creditCardName}"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -150,14 +136,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<sf:validateAllOnClick>
|
||||
<sf:commandButton id="proceed" action="proceed" processIds="*" value="Proceed"/> 
|
||||
</sf:validateAllOnClick>
|
||||
<sf:commandButton id="cancel" value="Cancel" action="cancel"/>
|
||||
<h:commandButton id="proceed" action="proceed" value="Proceed">
|
||||
<f:ajax render=":bookingsFragment" execute="@form" />
|
||||
</h:commandButton> 
|
||||
<h:commandButton id="cancel" value="Cancel" action="cancel" immediate="true" />
|
||||
</div>
|
||||
</fieldset>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
</h:panelGroup>
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
@@ -3,7 +3,6 @@
|
||||
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">
|
||||
@@ -70,7 +69,7 @@
|
||||
<div>
|
||||
<h:commandButton id="confirm" value="Confirm" action="confirm"/> 
|
||||
<h:commandButton id="revise" value="Revise" action="revise"/> 
|
||||
<h:commandButton id="cancel" value="Cancel" action="cancel"/>
|
||||
<h:commandButton id="cancel" value="Cancel" action="cancel" />
|
||||
</div>
|
||||
</fieldset>
|
||||
</h:form>
|
||||
|
||||
@@ -3,81 +3,78 @@
|
||||
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">
|
||||
<h2>Search Hotels</h2>
|
||||
<span class="errors">
|
||||
<h:messages globalOnly="true" />
|
||||
</span>
|
||||
<h:form id="mainForm" styleClass="inline">
|
||||
<fieldset>
|
||||
<div class="span-8">
|
||||
<h:outputLabel for="searchString">Search String: </h:outputLabel>
|
||||
<sf:clientTextValidator promptMessage="Search hotels by name, address, city, or zip.">
|
||||
<h:inputText id="searchString" value="#{searchCriteria.searchString}" />
|
||||
</sf:clientTextValidator>
|
||||
</div>
|
||||
<div class="span-6">
|
||||
<h:outputLabel for="pageSize">Maximum Results: </h:outputLabel>
|
||||
<h:selectOneMenu id="pageSize" value="#{searchCriteria.pageSize}">
|
||||
<f:selectItems value="#{referenceData.pageSizeOptions}" />
|
||||
</h:selectOneMenu>
|
||||
</div>
|
||||
<div class="span-3 last">
|
||||
<sf:commandButton id="findHotels" value="Find Hotels" processIds="*" action="search" />
|
||||
</div>
|
||||
</fieldset>
|
||||
</h:form>
|
||||
</div>
|
||||
</ui:fragment>
|
||||
<h:panelGroup id="hotelSearch" layout="block">
|
||||
<h2>Search Hotels</h2>
|
||||
<span class="errors">
|
||||
<h:messages globalOnly="true" />
|
||||
</span>
|
||||
<h:form id="mainForm" styleClass="inline">
|
||||
<fieldset>
|
||||
<div class="span-8">
|
||||
<h:outputLabel for="searchString">Search String: </h:outputLabel>
|
||||
<h:inputText id="searchString" value="#{searchCriteria.searchString}" />
|
||||
</div>
|
||||
<div class="span-6">
|
||||
<h:outputLabel for="pageSize">Maximum Results: </h:outputLabel>
|
||||
<h:selectOneMenu id="pageSize" value="#{searchCriteria.pageSize}">
|
||||
<f:selectItems value="#{referenceData.pageSizeOptions}" />
|
||||
</h:selectOneMenu>
|
||||
</div>
|
||||
<div class="span-3 last">
|
||||
<h:commandButton id="findHotels" value="Find Hotels" action="search" >
|
||||
<f:ajax render="@form" execute="@form" />
|
||||
</h:commandButton>
|
||||
</div>
|
||||
</fieldset>
|
||||
</h:form>
|
||||
</h:panelGroup>
|
||||
|
||||
<ui:fragment id="bookingsFragment" rendered="#{currentUser!=null}">
|
||||
<div id="bookingsSection">
|
||||
<h2>Current Hotel Bookings</h2>
|
||||
<h:outputText value="No Bookings Found" rendered="#{bookings.rowCount==0}"/>
|
||||
<h:form id="bookingsForm" rendered="#{bookings.rowCount > 0}">
|
||||
<h:dataTable id="bookings" styleClass="summary" value="#{bookings}" var="booking">
|
||||
<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>
|
||||
<h:panelGroup id="bookingsFragment" rendered="#{currentUser!=null}" layout="block">
|
||||
<h2>Current Hotel Bookings</h2>
|
||||
<h:outputText value="No Bookings Found" rendered="#{bookings.rowCount==0}"/>
|
||||
<h:form id="bookingsForm" rendered="#{bookings.rowCount > 0}">
|
||||
<h:dataTable id="bookings" styleClass="summary" value="#{bookings}" var="booking">
|
||||
<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>
|
||||
<h:commandLink id="cancel" value="Cancel" action="cancelBooking">
|
||||
<f:ajax render=":bookingsFragment" />
|
||||
</h:commandLink>
|
||||
</h:column>
|
||||
</h:dataTable>
|
||||
</h:form>
|
||||
</h:panelGroup>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
@@ -24,20 +24,17 @@
|
||||
</on-render>
|
||||
<transition on="sort">
|
||||
<set name="searchCriteria.sortBy" value="requestParameters.sortBy" />
|
||||
<render fragments="hotels:searchResultsFragment" />
|
||||
</transition>
|
||||
<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" />
|
||||
<transition on="changeSearch" to="enterSearchCriteria" />
|
||||
</view-state>
|
||||
|
||||
<view-state id="reviewHotel">
|
||||
@@ -50,15 +47,6 @@
|
||||
<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" />
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
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">
|
||||
|
||||
@@ -3,60 +3,60 @@
|
||||
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">
|
||||
<h:form id="hotelResults">
|
||||
<div>
|
||||
<h2>Hotel Results</h2>
|
||||
<p>
|
||||
<sf:commandLink value="Change Search" action="changeSearch"/>
|
||||
<h: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">
|
||||
<sf:commandLink id="sortByNameLink" action="sort" value="Name" processIds="*">
|
||||
<f:param name="sortBy" value="name" />
|
||||
</sf:commandLink>
|
||||
</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">
|
||||
<sf:commandLink id="sortByCity" action="sort" value="City, State" processIds="*" >
|
||||
<f:param name="sortBy" value="city" />
|
||||
</sf:commandLink>
|
||||
</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">
|
||||
<div class="span-3">
|
||||
<sf:commandLink id="previousPageLink" value="Previous results" action="previous" rendered="#{searchCriteria.page > 0}"/>
|
||||
</div>
|
||||
<div class="span-15 last">
|
||||
<sf:commandLink id="nextPageLink" value="More Results" action="next" rendered="#{not empty hotels and hotels.rowCount == searchCriteria.pageSize}"/>
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<h:commandLink id="sortByNameLink" action="sort" value="Name">
|
||||
<f:param name="sortBy" value="name" />
|
||||
<f:ajax render="hotels" />
|
||||
</h:commandLink>
|
||||
</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">
|
||||
<h:commandLink id="sortByCity" action="sort" value="City, State">
|
||||
<f:param name="sortBy" value="city" />
|
||||
<f:ajax render="hotels" />
|
||||
</h:commandLink>
|
||||
</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>
|
||||
<h:commandLink id="viewHotelLink" value="View Hotel" action="select"/>
|
||||
</h:column>
|
||||
</h:dataTable>
|
||||
<div class="buttonGroup">
|
||||
<h:commandLink id="previousPageLink" value="Previous Results" action="previous" rendered="#{searchCriteria.page > 0}">
|
||||
<f:ajax render="@form" />
|
||||
</h:commandLink>
|
||||
|
||||
<h:commandLink id="nextPageLink" value="More Results" action="next" rendered="#{not empty hotels and hotels.rowCount == searchCriteria.pageSize}">
|
||||
<f:ajax render="@form" />
|
||||
</h:commandLink>
|
||||
</div>
|
||||
</ui:fragment>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
xmlns:sf="http://www.springframework.org/tags/faces"
|
||||
contentType="text/html" encoding="UTF-8">
|
||||
<html>
|
||||
<head>
|
||||
<h:head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Spring Faces: Hotel Booking Sample Application</title>
|
||||
<sf:includeStyles/>
|
||||
@@ -18,7 +18,7 @@
|
||||
<![endif]-->
|
||||
<link rel="stylesheet" href="${request.contextPath}/styles/booking.css" type="text/css" media="screen" />
|
||||
<ui:insert name="headIncludes"/>
|
||||
</head>
|
||||
</h:head>
|
||||
<body class="tundra">
|
||||
<div id="page" class="container">
|
||||
<div id="header">
|
||||
|
||||
@@ -17,7 +17,7 @@ input[type=submit] {
|
||||
color: #fff;
|
||||
background: #fff url(../images/btn.bg.gif) 0 0 repeat-x;
|
||||
border-style: none;
|
||||
margin:0.4em 0;
|
||||
margin:0.4em 0.4em 0.4em 0;
|
||||
height: 1.8em;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user