From 0f84b153b550995132c78f4d6d6c54243a5ac335 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 17 May 2010 10:23:15 +0000 Subject: [PATCH] SWF-1194 Upgrade to JSF 2 --- build-spring-webflow/ivysettings.xml | 17 ++ build.properties | 3 +- spring-faces/.classpath | 6 +- .../.settings/org.eclipse.jdt.core.prefs | 12 +- spring-faces/ivy.xml | 8 +- spring-faces/pom.xml | 5 +- .../faces/ui/AjaxJsf2ViewRoot.java | 178 ++++++++++++++++++ .../faces/ui/DelegatingViewRoot.java | 7 +- .../faces/webflow/ExternalContextWrapper.java | 110 +++++++++++ .../faces/webflow/FlowApplicationFactory.java | 4 + .../faces/webflow/FlowFacesContext.java | 64 +++++++ .../faces/webflow/FlowViewStateManager.java | 1 + .../faces/webflow/JsfUtils.java | 15 +- .../faces/webflow/JsfVersion.java | 68 +++++++ .../faces/webflow/JsfViewFactory.java | 4 +- .../SelectionTrackingActionListenerTests.java | 17 +- .../faces/ui/AjaxViewRootTests.java | 2 +- .../ProgressiveCommandLinkRendererTests.java | 2 +- .../ui/resource/FlowResourceHelperTests.java | 2 +- .../faces/webflow/JSFMockHelper.java | 68 ++++--- .../faces/webflow/JsfViewTests.java | 6 +- .../faces/webflow/MockBaseFacesContext.java | 10 +- .../webflow/MockBaseFacesContextFactory.java | 2 +- spring-faces/template.mf | 2 +- .../booking-faces/build.xml | 4 +- spring-webflow-samples/booking-faces/ivy.xml | 4 +- .../src/main/webapp/WEB-INF/web.xml | 13 +- spring-webflow-samples/booking-mvc/build.xml | 3 +- .../booking-portlet-faces/build.xml | 1 + .../booking-portlet-mvc/build.xml | 1 + spring-webflow-samples/jsf-booking/build.xml | 1 + spring-webflow-samples/jsf-booking/ivy.xml | 4 +- .../src/main/webapp/WEB-INF/web.xml | 14 +- 33 files changed, 576 insertions(+), 82 deletions(-) create mode 100644 build-spring-webflow/ivysettings.xml create mode 100644 spring-faces/src/main/java/org/springframework/faces/ui/AjaxJsf2ViewRoot.java create mode 100644 spring-faces/src/main/java/org/springframework/faces/webflow/JsfVersion.java diff --git a/build-spring-webflow/ivysettings.xml b/build-spring-webflow/ivysettings.xml new file mode 100644 index 00000000..41938115 --- /dev/null +++ b/build-spring-webflow/ivysettings.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/build.properties b/build.properties index 5524f674..0bc149b7 100644 --- a/build.properties +++ b/build.properties @@ -4,10 +4,11 @@ natural.name=spring-webflow project.key=SWF ivy.cache.dir=${basedir}/../ivy-cache integration.repo.dir=${basedir}/../integration-repo -source.version=1.4 +source.version=1.5 javadoc.exclude.package.names=org/springframework/webflow/samples/** javadoc.max.memory=256M test.vm.args=-XX:MaxPermSize=128M +ivy.settings.file=${basedir}/../build-spring-webflow/ivysettings.xml # For when releasing #release.type=release diff --git a/spring-faces/.classpath b/spring-faces/.classpath index 3e1988ee..72a3bc81 100644 --- a/spring-faces/.classpath +++ b/spring-faces/.classpath @@ -9,8 +9,8 @@ - - + + @@ -18,7 +18,7 @@ - + diff --git a/spring-faces/.settings/org.eclipse.jdt.core.prefs b/spring-faces/.settings/org.eclipse.jdt.core.prefs index e61c6b14..ae652523 100644 --- a/spring-faces/.settings/org.eclipse.jdt.core.prefs +++ b/spring-faces/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,4 @@ -#Thu Jul 10 09:40:54 BST 2008 +#Fri May 14 17:56:46 BST 2010 eclipse.preferences.version=1 org.eclipse.jdt.core.codeComplete.argumentPrefixes= org.eclipse.jdt.core.codeComplete.argumentSuffixes= @@ -9,22 +9,22 @@ org.eclipse.jdt.core.codeComplete.localSuffixes= org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.4 +org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.doc.comment.support=enabled org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning -org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.autoboxing=ignore org.eclipse.jdt.core.compiler.problem.deprecation=warning org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled org.eclipse.jdt.core.compiler.problem.discouragedReference=warning org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore -org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning @@ -79,7 +79,7 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=di org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.3 +org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/spring-faces/ivy.xml b/spring-faces/ivy.xml index d78698cc..b59f71f5 100644 --- a/spring-faces/ivy.xml +++ b/spring-faces/ivy.xml @@ -11,6 +11,7 @@ + @@ -37,6 +38,10 @@ + + + + @@ -48,6 +53,7 @@ + @@ -55,4 +61,4 @@ - \ No newline at end of file + diff --git a/spring-faces/pom.xml b/spring-faces/pom.xml index f05f7492..e29b4659 100644 --- a/spring-faces/pom.xml +++ b/spring-faces/pom.xml @@ -84,13 +84,13 @@ javax.faces jsf-api - ${jsf.version} + 2.0 provided javax.faces jsf-impl - ${jsf.version} + 2.0.2 provided @@ -114,6 +114,5 @@ 3.0.2.RELEASE - 1.2_09 diff --git a/spring-faces/src/main/java/org/springframework/faces/ui/AjaxJsf2ViewRoot.java b/spring-faces/src/main/java/org/springframework/faces/ui/AjaxJsf2ViewRoot.java new file mode 100644 index 00000000..db5bab97 --- /dev/null +++ b/spring-faces/src/main/java/org/springframework/faces/ui/AjaxJsf2ViewRoot.java @@ -0,0 +1,178 @@ +/* + * 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; + +import org.springframework.faces.webflow.JsfVersion; + +/** + *

+ * A subclass of AjaxViewRoot for use with JSF 2.0. + *

+ * + *

+ * 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. + *

+ * + * @author Phil Webb + */ +public class AjaxJsf2ViewRoot extends AjaxViewRoot { + + public AjaxJsf2ViewRoot(UIViewRoot original) { + super(original); + if (JsfVersion.isAtLeastJsf20()) { + setId(createUniqueId()); + } + } + + 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); + } + +} diff --git a/spring-faces/src/main/java/org/springframework/faces/ui/DelegatingViewRoot.java b/spring-faces/src/main/java/org/springframework/faces/ui/DelegatingViewRoot.java index f339def7..29a197b6 100644 --- a/spring-faces/src/main/java/org/springframework/faces/ui/DelegatingViewRoot.java +++ b/spring-faces/src/main/java/org/springframework/faces/ui/DelegatingViewRoot.java @@ -71,7 +71,7 @@ public abstract class DelegatingViewRoot extends UIViewRoot { * @see javax.faces.component.UIViewRoot#createUniqueId() */ public String createUniqueId() { - return original.createUniqueId(); + return (original != null) ? original.createUniqueId() : null; } /** @@ -409,7 +409,10 @@ public abstract class DelegatingViewRoot extends UIViewRoot { * @see javax.faces.component.UIComponentBase#setId(java.lang.String) */ public void setId(String id) { - original.setId(id); + // Test for null to deal with JSF setId on constructor + if (original != null) { + original.setId(id); + } } /** diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/ExternalContextWrapper.java b/spring-faces/src/main/java/org/springframework/faces/webflow/ExternalContextWrapper.java index e1e202b5..9a18032d 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/ExternalContextWrapper.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/ExternalContextWrapper.java @@ -2,7 +2,9 @@ package org.springframework.faces.webflow; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.security.Principal; @@ -12,6 +14,7 @@ import java.util.Map; import java.util.Set; import javax.faces.context.ExternalContext; +import javax.faces.context.Flash; class ExternalContextWrapper extends ExternalContext { @@ -188,4 +191,111 @@ class ExternalContextWrapper extends ExternalContext { public void setResponseCharacterEncoding(String encoding) { delegate.setResponseCharacterEncoding(encoding); } + + // --------------- JSF 2.0 Pass-through delegate methods ------------------// + + public String getContextName() { + return delegate.getContextName(); + } + + public void addResponseCookie(String name, String value, Map properties) { + delegate.addResponseCookie(name, value, properties); + } + + public Flash getFlash() { + return delegate.getFlash(); + } + + public String getMimeType(String file) { + return delegate.getMimeType(file); + } + + public String getRequestScheme() { + return delegate.getRequestScheme(); + } + + public String getRequestServerName() { + return delegate.getRequestServerName(); + } + + public int getRequestServerPort() { + return delegate.getRequestServerPort(); + } + + public String getRealPath(String path) { + return delegate.getRealPath(path); + } + + public int getRequestContentLength() { + return delegate.getRequestContentLength(); + } + + public OutputStream getResponseOutputStream() throws IOException { + return delegate.getResponseOutputStream(); + } + + public Writer getResponseOutputWriter() throws IOException { + return delegate.getResponseOutputWriter(); + } + + public void setResponseContentType(String contentType) { + delegate.setResponseContentType(contentType); + } + + public void invalidateSession() { + delegate.invalidateSession(); + } + + public void setResponseHeader(String name, String value) { + delegate.setResponseHeader(name, value); + } + + public void addResponseHeader(String name, String value) { + delegate.addResponseHeader(name, value); + } + + public void setResponseBufferSize(int size) { + delegate.setResponseBufferSize(size); + } + + public int getResponseBufferSize() { + return delegate.getResponseBufferSize(); + } + + public boolean isResponseCommitted() { + return delegate.isResponseCommitted(); + } + + public void responseReset() { + delegate.responseReset(); + } + + public void responseSendError(int statusCode, String message) throws IOException { + delegate.responseSendError(statusCode, message); + } + + public void setResponseStatus(int statusCode) { + delegate.setResponseStatus(statusCode); + } + + public void responseFlushBuffer() throws IOException { + delegate.responseFlushBuffer(); + } + + public void setResponseContentLength(int length) { + delegate.setResponseContentLength(length); + } + + public String encodeBookmarkableURL(String baseUrl, Map parameters) { + return delegate.encodeBookmarkableURL(baseUrl, parameters); + } + + public String encodeRedirectURL(String baseUrl, Map parameters) { + return delegate.encodeRedirectURL(baseUrl, parameters); + } + + public String encodePartialActionURL(String url) { + return delegate.encodePartialActionURL(url); + } + } diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowApplicationFactory.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowApplicationFactory.java index 073665fc..3d99f735 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowApplicationFactory.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowApplicationFactory.java @@ -48,4 +48,8 @@ public class FlowApplicationFactory extends ApplicationFactory { delegate.setApplication(application); } + public ApplicationFactory getWrapped() { + return delegate; + } + } diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java index 48ec0f87..a0e2f4d3 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowFacesContext.java @@ -17,17 +17,23 @@ package org.springframework.faces.webflow; import java.lang.reflect.Method; import java.util.Iterator; +import java.util.List; +import java.util.Map; import javax.el.ELContext; import javax.faces.FactoryFinder; import javax.faces.application.Application; import javax.faces.application.FacesMessage; +import javax.faces.application.ProjectStage; import javax.faces.component.UIViewRoot; +import javax.faces.context.ExceptionHandler; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.context.FacesContextFactory; +import javax.faces.context.PartialViewContext; import javax.faces.context.ResponseStream; import javax.faces.context.ResponseWriter; +import javax.faces.event.PhaseId; import javax.faces.lifecycle.Lifecycle; import javax.faces.render.RenderKit; @@ -199,6 +205,64 @@ public class FlowFacesContext extends FacesContext { return delegate; } + // --------------- JSF 2.0 Pass-through delegate methods ------------------// + + public Map getAttributes() { + return delegate.getAttributes(); + } + + public PartialViewContext getPartialViewContext() { + return delegate.getPartialViewContext(); + } + + public List getMessageList() { + return delegate.getMessageList(); + } + + public List getMessageList(String clientId) { + return delegate.getMessageList(clientId); + } + + public boolean isPostback() { + return delegate.isPostback(); + } + + public PhaseId getCurrentPhaseId() { + return delegate.getCurrentPhaseId(); + } + + public void setCurrentPhaseId(PhaseId currentPhaseId) { + delegate.setCurrentPhaseId(currentPhaseId); + } + + public ExceptionHandler getExceptionHandler() { + return delegate.getExceptionHandler(); + } + + public boolean isProcessingEvents() { + return delegate.isProcessingEvents(); + } + + public boolean isProjectStage(ProjectStage stage) { + return delegate.isProjectStage(stage); + } + + public boolean isValidationFailed() { + return delegate.isValidationFailed(); + } + + public void setExceptionHandler(ExceptionHandler exceptionHandler) { + delegate.setExceptionHandler(exceptionHandler); + } + + public void setProcessingEvents(boolean processingEvents) { + delegate.setProcessingEvents(processingEvents); + } + + public void validationFailed() { + delegate.validationFailed(); + } + // ------------------ Private helper methods ----------------------// private class FlowExternalContext extends ExternalContextWrapper { diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java index 39662bbd..bc7b7875 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/FlowViewStateManager.java @@ -156,6 +156,7 @@ public class FlowViewStateManager extends StateManager { } UIViewRoot viewRoot = restoreTreeStructure(context, viewId, renderKitId); if (viewRoot != null) { + context.setViewRoot(viewRoot); restoreComponentState(context, viewRoot, renderKitId); } return viewRoot; diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfUtils.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfUtils.java index 0e92ce8d..61bc7e82 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfUtils.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfUtils.java @@ -21,7 +21,6 @@ import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.faces.lifecycle.Lifecycle; -import org.springframework.util.ReflectionUtils; import org.springframework.webflow.execution.RequestContextHolder; /** @@ -31,18 +30,6 @@ import org.springframework.webflow.execution.RequestContextHolder; */ public class JsfUtils { - private static final boolean JSF_12; - - private static final String JSF_12_METHOD = "getELContext"; - - static { - if (ReflectionUtils.findMethod(FacesContext.class, JSF_12_METHOD) != null) { - JSF_12 = true; - } else { - JSF_12 = false; - } - } - public static void notifyAfterListeners(PhaseId phaseId, Lifecycle lifecycle, FacesContext context) { PhaseEvent afterPhaseEvent = new PhaseEvent(context, phaseId, lifecycle); for (int i = 0; i < lifecycle.getPhaseListeners().length; i++) { @@ -80,7 +67,7 @@ public class JsfUtils { } public static boolean isAtLeastJsf12() { - return JSF_12; + return JsfVersion.isAtLeastJsf12(); } public static boolean isPortlet(FacesContext context) { diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfVersion.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfVersion.java new file mode 100644 index 00000000..85e7c65e --- /dev/null +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfVersion.java @@ -0,0 +1,68 @@ +/* + * 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.context.FacesContext; + +import org.springframework.util.ReflectionUtils; + +/** + * Internal helper class to find the version of JSF in use at runtime. + * + * @author Phil Webb + */ +public class JsfVersion { + + /** + * JSF Version 1.1 + */ + public static final int JSF_11 = 0; + + /** + * JSF Version 1.2 + */ + public static final int JSF_12 = 1; + + /** + * JSF Version 2.0 + */ + public static final int JSF_20 = 2; + + private static final int jsfVersion; + + static { + if (ReflectionUtils.findMethod(FacesContext.class, "isPostback") != null) { + jsfVersion = JsfVersion.JSF_20; + } else if (ReflectionUtils.findMethod(FacesContext.class, "getELContext") != null) { + jsfVersion = JsfVersion.JSF_12; + } else { + jsfVersion = JsfVersion.JSF_11; + } + } + + public static int getJsfVersion() { + return jsfVersion; + } + + public static boolean isAtLeastJsf20() { + return jsfVersion >= JSF_20; + } + + public static boolean isAtLeastJsf12() { + return jsfVersion >= JSF_12; + } + +} \ No newline at end of file diff --git a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactory.java b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactory.java index db663754..44e62be7 100644 --- a/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactory.java +++ b/spring-faces/src/main/java/org/springframework/faces/webflow/JsfViewFactory.java @@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.binding.expression.Expression; +import org.springframework.faces.ui.AjaxJsf2ViewRoot; import org.springframework.faces.ui.AjaxViewRoot; import org.springframework.js.ajax.SpringJavascriptAjaxHandler; import org.springframework.webflow.context.ExternalContext; @@ -136,7 +137,8 @@ public class JsfViewFactory implements ViewFactory { private JsfView createJsfView(UIViewRoot root, Lifecycle lifecycle, RequestContext context) { if (isSpringJavascriptAjaxRequest(context.getExternalContext())) { - return new JsfView(new AjaxViewRoot(root), lifecycle, context); + AjaxViewRoot viewRoot = (JsfVersion.isAtLeastJsf20()) ? new AjaxJsf2ViewRoot(root) : new AjaxViewRoot(root); + return new JsfView(viewRoot, lifecycle, context); } else { return new JsfView(root, lifecycle, context); } diff --git a/spring-faces/src/test/java/org/springframework/faces/model/SelectionTrackingActionListenerTests.java b/spring-faces/src/test/java/org/springframework/faces/model/SelectionTrackingActionListenerTests.java index 60e19e5a..07ff011f 100644 --- a/spring-faces/src/test/java/org/springframework/faces/model/SelectionTrackingActionListenerTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/model/SelectionTrackingActionListenerTests.java @@ -12,14 +12,20 @@ import javax.faces.event.AbortProcessingException; import javax.faces.event.ActionEvent; import javax.faces.event.ActionListener; +import junit.framework.TestCase; + +import org.springframework.faces.webflow.JSFMockHelper; import org.springframework.util.ReflectionUtils; import com.sun.facelets.component.UIRepeat; -import junit.framework.TestCase; - public class SelectionTrackingActionListenerTests extends TestCase { + /** + * JSF Mock Helper + */ + private JSFMockHelper jsfMockHelper = new JSFMockHelper(); + /** * The JSF view to simulate */ @@ -40,7 +46,8 @@ public class SelectionTrackingActionListenerTests extends TestCase { */ private ActionListener selectionTrackingListener = new SelectionTrackingActionListener(delegateListener); - public void setUp() { + public void setUp() throws Exception { + jsfMockHelper.setUp(); viewToTest = new UIViewRoot(); List rows = new ArrayList(); rows.add(new TestRowData()); @@ -49,6 +56,10 @@ public class SelectionTrackingActionListenerTests extends TestCase { dataModel = new OneSelectionTrackingListDataModel(rows); } + protected void tearDown() throws Exception { + jsfMockHelper.tearDown(); + } + public void testProcessActionWithUIData() { UIData dataTable = new UIData(); diff --git a/spring-faces/src/test/java/org/springframework/faces/ui/AjaxViewRootTests.java b/spring-faces/src/test/java/org/springframework/faces/ui/AjaxViewRootTests.java index 746d721b..5f709753 100644 --- a/spring-faces/src/test/java/org/springframework/faces/ui/AjaxViewRootTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/ui/AjaxViewRootTests.java @@ -10,7 +10,7 @@ import javax.faces.render.RenderKitFactory; import junit.framework.TestCase; -import org.apache.shale.test.mock.MockResponseWriter; +import org.apache.myfaces.test.mock.MockResponseWriter; import org.springframework.faces.webflow.JSFMockHelper; import org.springframework.faces.webflow.MockViewHandler; import org.springframework.util.StringUtils; diff --git a/spring-faces/src/test/java/org/springframework/faces/ui/ProgressiveCommandLinkRendererTests.java b/spring-faces/src/test/java/org/springframework/faces/ui/ProgressiveCommandLinkRendererTests.java index 2954fbac..93e1ec4c 100644 --- a/spring-faces/src/test/java/org/springframework/faces/ui/ProgressiveCommandLinkRendererTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/ui/ProgressiveCommandLinkRendererTests.java @@ -7,7 +7,7 @@ import javax.faces.component.UIParameter; import junit.framework.TestCase; -import org.apache.shale.test.mock.MockResponseWriter; +import org.apache.myfaces.test.mock.MockResponseWriter; import org.springframework.faces.webflow.JSFMockHelper; public class ProgressiveCommandLinkRendererTests extends TestCase { diff --git a/spring-faces/src/test/java/org/springframework/faces/ui/resource/FlowResourceHelperTests.java b/spring-faces/src/test/java/org/springframework/faces/ui/resource/FlowResourceHelperTests.java index bd1ec147..dd49babe 100644 --- a/spring-faces/src/test/java/org/springframework/faces/ui/resource/FlowResourceHelperTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/ui/resource/FlowResourceHelperTests.java @@ -5,7 +5,7 @@ import java.io.StringWriter; import junit.framework.TestCase; -import org.apache.shale.test.mock.MockResponseWriter; +import org.apache.myfaces.test.mock.MockResponseWriter; import org.springframework.faces.webflow.JSFMockHelper; public class FlowResourceHelperTests extends TestCase { diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java index f510d3fd..548c3868 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java @@ -1,30 +1,37 @@ package org.springframework.faces.webflow; +import java.net.URL; +import java.net.URLClassLoader; + import javax.faces.FactoryFinder; import javax.faces.application.Application; +import javax.faces.application.ApplicationFactory; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; import javax.faces.context.FacesContextFactory; import javax.faces.lifecycle.LifecycleFactory; import javax.faces.render.RenderKitFactory; -import org.apache.shale.test.base.AbstractJsfTestCase; -import org.apache.shale.test.mock.MockApplication; -import org.apache.shale.test.mock.MockExternalContext; -import org.apache.shale.test.mock.MockHttpServletRequest; -import org.apache.shale.test.mock.MockHttpServletResponse; -import org.apache.shale.test.mock.MockHttpSession; -import org.apache.shale.test.mock.MockLifecycle; -import org.apache.shale.test.mock.MockLifecycleFactory; -import org.apache.shale.test.mock.MockRenderKit; -import org.apache.shale.test.mock.MockServletConfig; -import org.apache.shale.test.mock.MockServletContext; +import org.apache.myfaces.test.base.AbstractJsfTestCase; +import org.apache.myfaces.test.mock.MockApplicationFactory; +import org.apache.myfaces.test.mock.MockExternalContext; +import org.apache.myfaces.test.mock.MockHttpServletRequest; +import org.apache.myfaces.test.mock.MockHttpServletResponse; +import org.apache.myfaces.test.mock.MockHttpSession; +import org.apache.myfaces.test.mock.MockPartialViewContextFactory; +import org.apache.myfaces.test.mock.MockRenderKit; +import org.apache.myfaces.test.mock.MockRenderKitFactory; +import org.apache.myfaces.test.mock.MockServletConfig; +import org.apache.myfaces.test.mock.MockServletContext; +import org.apache.myfaces.test.mock.lifecycle.MockLifecycle; +import org.apache.myfaces.test.mock.lifecycle.MockLifecycleFactory; /** * Helper for using the mock JSF environment provided by shale-test inside unit tests that do not extend * {@link AbstractJsfTestCase} - * @author Jeremy Grelle * + * @author Jeremy Grelle + * @author Phil Webb */ public class JSFMockHelper { @@ -88,17 +95,21 @@ public class JSFMockHelper { private static class JSFMock extends AbstractJsfTestCase { + private ClassLoader threadContextClassLoader; + public JSFMock() { super("JSFMock"); } - FacesContextFactory facesContextFactory; FacesContext facesContext; + FacesContextFactory facesContextFactory; public void setUp() throws Exception { - // Thread.currentThread().setContextClassLoader( - // new URLClassLoader(new URL[0], this.getClass().getClassLoader())); + // Set up a new thread context class loader + threadContextClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader( + new URLClassLoader(new URL[0], this.getClass().getClassLoader())); // Set up Servlet API Objects servletContext = new MockServletContext(); @@ -110,20 +121,12 @@ public class JSFMockHelper { response = new MockHttpServletResponse(); // Set up JSF API Objects - FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, - "org.apache.shale.test.mock.MockApplicationFactory"); - FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY, - "org.springframework.faces.webflow.MockBaseFacesContextFactory"); - /* - * FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY, - * "org.apache.shale.test.mock.MockFacesContextFactory"); - */ - FactoryFinder - .setFactory(FactoryFinder.LIFECYCLE_FACTORY, "org.apache.shale.test.mock.MockLifecycleFactory"); - FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, - "org.apache.shale.test.mock.MockRenderKitFactory"); - - application = new MockApplication(); + FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY, MockApplicationFactory.class.getName()); + FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY, MockBaseFacesContextFactory.class.getName()); + FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY, MockLifecycleFactory.class.getName()); + 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); @@ -134,6 +137,9 @@ public class JSFMockHelper { root.setViewId("/viewId"); root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT); facesContext.setViewRoot(root); + ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder + .getFactory(FactoryFinder.APPLICATION_FACTORY); + application = (org.apache.myfaces.test.mock.MockApplication) applicationFactory.getApplication(); RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder .getFactory(FactoryFinder.RENDER_KIT_FACTORY); renderKit = new MockRenderKit(); @@ -157,9 +163,11 @@ public class JSFMockHelper { session = null; FactoryFinder.releaseFactories(); + Thread.currentThread().setContextClassLoader(threadContextClassLoader); + threadContextClassLoader = null; } - public MockApplication application() { + public org.apache.myfaces.test.mock.MockApplication application() { return application; } diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewTests.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewTests.java index bbbd8199..1516b078 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewTests.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JsfViewTests.java @@ -14,8 +14,8 @@ import javax.faces.lifecycle.Lifecycle; import junit.framework.TestCase; -import org.apache.shale.test.mock.MockResponseWriter; -import org.apache.shale.test.mock.MockStateManager; +import org.apache.myfaces.test.mock.MockResponseWriter; +import org.apache.myfaces.test.mock.MockStateManager; import org.easymock.EasyMock; import org.springframework.faces.ui.AjaxViewRoot; import org.springframework.webflow.core.collection.MutableAttributeMap; @@ -130,7 +130,7 @@ public class JsfViewTests extends TestCase { try { view.render(); - } catch (FacesException ex) { + } catch (Exception ex) { assertNull("The FacesContext was not released", FacesContext.getCurrentInstance()); } } diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContext.java b/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContext.java index 23c76725..7b4fbe08 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContext.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContext.java @@ -1,14 +1,16 @@ package org.springframework.faces.webflow; +import java.util.Map; + import javax.faces.FactoryFinder; import javax.faces.application.Application; import javax.faces.application.ApplicationFactory; import javax.faces.context.ExternalContext; import javax.faces.lifecycle.Lifecycle; -import org.apache.shale.test.mock.MockFacesContext12; +import org.apache.myfaces.test.mock.MockFacesContext20; -public class MockBaseFacesContext extends MockFacesContext12 { +public class MockBaseFacesContext extends MockFacesContext20 { private Application application; @@ -24,6 +26,10 @@ public class MockBaseFacesContext extends MockFacesContext12 { super(externalContext, lifecycle); } + public Map getAttributes() { + return super.getAttributes(); + } + public Application getApplication() { if (application == null) { ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContextFactory.java b/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContextFactory.java index 6c2e5e82..b832ee58 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContextFactory.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/MockBaseFacesContextFactory.java @@ -9,7 +9,7 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.shale.test.mock.MockExternalContext; +import org.apache.myfaces.test.mock.MockExternalContext; public class MockBaseFacesContextFactory extends FacesContextFactory { diff --git a/spring-faces/template.mf b/spring-faces/template.mf index 25f50c68..76ac0df9 100644 --- a/spring-faces/template.mf +++ b/spring-faces/template.mf @@ -13,7 +13,7 @@ Import-Template: javax.el;version="[1.0.0, 2.0.0)", javax.servlet;version="[2.4.0, 3.0.0)", javax.servlet.http;version="[2.4.0, 3.0.0)", - javax.faces.*;version="[1.2.0, 2.0.0)", + javax.faces.*;version="[1.2.0, 3.0.0)", org.ajax4jsf.*;version="[1.1.1, 2.0.0)";resolution:=optional, com.sun.facelets.*;version="[1.1.0, 2.0.0)";resolution:=optional, org.w3c.dom;version="0" diff --git a/spring-webflow-samples/booking-faces/build.xml b/spring-webflow-samples/booking-faces/build.xml index 89925390..f1d81986 100755 --- a/spring-webflow-samples/booking-faces/build.xml +++ b/spring-webflow-samples/booking-faces/build.xml @@ -4,10 +4,12 @@ + + - + diff --git a/spring-webflow-samples/booking-faces/ivy.xml b/spring-webflow-samples/booking-faces/ivy.xml index 726f65a3..32e20645 100755 --- a/spring-webflow-samples/booking-faces/ivy.xml +++ b/spring-webflow-samples/booking-faces/ivy.xml @@ -46,7 +46,7 @@ - + @@ -57,4 +57,4 @@ - \ No newline at end of file + diff --git a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/web.xml b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/web.xml index 5dd05220..9efa7c31 100755 --- a/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/web.xml +++ b/spring-webflow-samples/booking-faces/src/main/webapp/WEB-INF/web.xml @@ -26,7 +26,7 @@ - facelets.REFRESH_PERIOD + javax.faces.FACELETS_REFRESH_PERIOD 1 @@ -59,7 +59,18 @@ springSecurityFilterChain /* + + + + com.sun.faces.config.ConfigureListener + + + org.springframework.web.context.ContextLoaderListener diff --git a/spring-webflow-samples/booking-mvc/build.xml b/spring-webflow-samples/booking-mvc/build.xml index 2e9cccb9..914de0de 100755 --- a/spring-webflow-samples/booking-mvc/build.xml +++ b/spring-webflow-samples/booking-mvc/build.xml @@ -4,10 +4,11 @@ + - + diff --git a/spring-webflow-samples/booking-portlet-faces/build.xml b/spring-webflow-samples/booking-portlet-faces/build.xml index 12b51ebd..e27197ce 100644 --- a/spring-webflow-samples/booking-portlet-faces/build.xml +++ b/spring-webflow-samples/booking-portlet-faces/build.xml @@ -4,6 +4,7 @@ + diff --git a/spring-webflow-samples/booking-portlet-mvc/build.xml b/spring-webflow-samples/booking-portlet-mvc/build.xml index 793a03a5..e28d39cd 100644 --- a/spring-webflow-samples/booking-portlet-mvc/build.xml +++ b/spring-webflow-samples/booking-portlet-mvc/build.xml @@ -4,6 +4,7 @@ + diff --git a/spring-webflow-samples/jsf-booking/build.xml b/spring-webflow-samples/jsf-booking/build.xml index 2ff6d566..d48f90c3 100644 --- a/spring-webflow-samples/jsf-booking/build.xml +++ b/spring-webflow-samples/jsf-booking/build.xml @@ -4,6 +4,7 @@ + diff --git a/spring-webflow-samples/jsf-booking/ivy.xml b/spring-webflow-samples/jsf-booking/ivy.xml index 78dc3fba..8f5b8b1b 100644 --- a/spring-webflow-samples/jsf-booking/ivy.xml +++ b/spring-webflow-samples/jsf-booking/ivy.xml @@ -23,8 +23,8 @@ - - + + diff --git a/spring-webflow-samples/jsf-booking/src/main/webapp/WEB-INF/web.xml b/spring-webflow-samples/jsf-booking/src/main/webapp/WEB-INF/web.xml index 7bfe3828..06b4937b 100644 --- a/spring-webflow-samples/jsf-booking/src/main/webapp/WEB-INF/web.xml +++ b/spring-webflow-samples/jsf-booking/src/main/webapp/WEB-INF/web.xml @@ -25,10 +25,22 @@ - facelets.REFRESH_PERIOD + javax.faces.FACELETS_REFRESH_PERIOD 1 + + + + com.sun.faces.config.ConfigureListener + + + + org.springframework.web.context.ContextLoaderListener