Upgrade to JSF/Mojarra 2.2

Issue: SWF-1613
This commit is contained in:
Rossen Stoyanchev
2014-01-21 21:07:12 -05:00
parent 25ac1cc797
commit 0d99f72391
6 changed files with 84 additions and 17 deletions

View File

@@ -208,8 +208,8 @@ project("spring-faces") {
provided("javax.el:el-api:1.0")
provided("javax.servlet:javax.servlet-api:3.0.1")
provided("javax.portlet:portlet-api:2.0")
provided("com.sun.faces:jsf-api:2.1.7")
provided("com.sun.faces:jsf-impl:2.1.7")
provided("com.sun.faces:jsf-api:2.2.5")
provided("com.sun.faces:jsf-impl:2.2.5")
provided("org.apache.myfaces.core:myfaces-impl:2.1.7")
optional("com.sun.facelets:jsf-facelets:1.1.14")
optional("org.richfaces.framework:richfaces-api:3.1.4.GA")

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2010 the original author or authors.
* Copyright 2004-2014 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.
@@ -22,18 +22,35 @@ import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.RequestContext;
/**
* A {@link FlowExecutionListener} that creates a {@link FlowFacesContext} instance when a flow request is submitted and
* releases it when the request has been processed.
* A {@link FlowExecutionListener} that creates a {@link FlowFacesContext}
* instance when a flow request is submitted and releases it when the request
* has been processed.
*
* @author Rossen Stoyanchev
*/
public class FlowFacesContextLifecycleListener extends FlowExecutionListenerAdapter {
public static final String DEFAULT_FACES_CONTEXT =
FlowFacesContextLifecycleListener.class.getName() + ".DEFAULT_FACES_CONTEXT";
/**
* Creates a new instance of {@link FlowFacesContext} that is then available for the duration of the request.
* @param context the current flow request context
*/
public void requestSubmitted(RequestContext context) {
FacesContext facesContext = getRequestFacesContext(context);
if (facesContext != null) {
// FacesContext already created, just wrap it (sets "current" instance internally)
if (JsfRuntimeInformation.isAtLeastJsf20()) {
new Jsf2FlowFacesContext(context, facesContext);
}
else {
new FlowFacesContext(context, facesContext);
}
return;
}
FlowFacesContext.newInstance(context, FlowLifecycle.newInstance());
}
@@ -42,7 +59,15 @@ public class FlowFacesContextLifecycleListener extends FlowExecutionListenerAdap
* @param context the source of the event
*/
public void requestProcessed(RequestContext context) {
if (getRequestFacesContext(context) != null) {
return;
}
FacesContext.getCurrentInstance().release();
}
private FacesContext getRequestFacesContext(RequestContext context) {
return (FacesContext) context.getExternalContext().getRequestMap().get(DEFAULT_FACES_CONTEXT);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2010 the original author or authors.
* Copyright 2004-2014 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.
@@ -31,6 +31,7 @@ import javax.faces.context.Flash;
import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextFactory;
import javax.faces.event.PhaseId;
import javax.faces.lifecycle.ClientWindow;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -265,5 +266,23 @@ public class Jsf2FlowFacesContext extends FlowFacesContext {
public void setSessionMaxInactiveInterval(int interval) {
delegate.setSessionMaxInactiveInterval(interval);
}
// --------------- JSF 2.2 Pass-through delegate methods ------------------//
public String getApplicationContextPath() {
return delegate.getApplicationContextPath();
}
public String getSessionId(boolean create) {
return delegate.getSessionId(create);
}
public ClientWindow getClientWindow() {
return delegate.getClientWindow();
}
public void setClientWindow(ClientWindow window) {
delegate.setClientWindow(window);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2010 the original author or authors.
* Copyright 2004-2014 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.
@@ -19,6 +19,8 @@ import java.io.IOException;
import java.net.URL;
import javax.faces.FacesException;
import javax.faces.application.ResourceHandler;
import javax.faces.context.FacesContext;
import javax.faces.view.facelets.ResourceResolver;
import org.springframework.context.ApplicationContext;
@@ -29,8 +31,8 @@ import org.springframework.webflow.execution.RequestContextHolder;
import com.sun.faces.facelets.impl.DefaultResourceResolver;
/**
* Resolves Facelets templates using Spring Resource paths such as "classpath:foo.xhtml". Configure it via a context
* parameter in web.xml:
* Resolves Facelets templates using Spring Resource paths such as "classpath:foo.xhtml".
* Configure it via a context parameter in web.xml:
*
* <pre>
* &lt;context-param/&gt;
@@ -41,11 +43,12 @@ import com.sun.faces.facelets.impl.DefaultResourceResolver;
*/
public class Jsf2FlowResourceResolver extends ResourceResolver {
ResourceResolver delegateResolver = new DefaultResourceResolver();
ResourceResolver delegateResolver;
public URL resolveUrl(String path) {
if (!JsfUtils.isFlowRequest()) {
initDelegateIfNecessary();
return delegateResolver.resolveUrl(path);
}
@@ -61,6 +64,7 @@ public class Jsf2FlowResourceResolver extends ResourceResolver {
if (viewResource.exists()) {
return viewResource.getURL();
} else {
initDelegateIfNecessary();
return delegateResolver.resolveUrl(path);
}
} catch (IOException ex) {
@@ -68,4 +72,12 @@ public class Jsf2FlowResourceResolver extends ResourceResolver {
}
}
private void initDelegateIfNecessary() {
if (this.delegateResolver == null) {
FacesContext facesContext = FacesContext.getCurrentInstance();
ResourceHandler resourceHandler = facesContext.getApplication().getResourceHandler();
this.delegateResolver = new DefaultResourceResolver(resourceHandler);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2004-2010 the original author or authors.
* Copyright 2004-2014 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.
@@ -15,6 +15,7 @@
*/
package org.springframework.faces.webflow;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -32,9 +33,11 @@ import org.springframework.webflow.mvc.servlet.FlowHandlerAdapter;
public class JsfFlowHandlerAdapter extends FlowHandlerAdapter {
public void afterPropertiesSet() throws Exception {
boolean initializeAjaxHandler = getAjaxHandler() == null;
boolean isAjaxHandlerConfigured = (getAjaxHandler() != null);
super.afterPropertiesSet();
if (initializeAjaxHandler) {
if (!isAjaxHandlerConfigured) {
if (JsfRuntimeInformation.isAtLeastJsf20()) {
JsfAjaxHandler ajaxHandler = new JsfAjaxHandler();
ajaxHandler.setApplicationContext(getApplicationContext());
@@ -45,7 +48,17 @@ public class JsfFlowHandlerAdapter extends FlowHandlerAdapter {
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return super.handle(request, response, handler);
FacesContextHelper helper = new FacesContextHelper();
try {
FacesContext facesContext = helper.getFacesContext(getServletContext(), request, response);
request.setAttribute(FlowFacesContextLifecycleListener.DEFAULT_FACES_CONTEXT, facesContext);
return super.handle(request, response, handler);
} finally {
request.removeAttribute(FlowFacesContextLifecycleListener.DEFAULT_FACES_CONTEXT);
helper.releaseIfNecessary();
}
}
}

View File

@@ -23,9 +23,7 @@ public class JsfAjaxHandlerTests extends TestCase {
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>",
jsfMock.contentAsString());
assertTrue(this.jsfMock.contentAsString().matches("<partial-response.*><redirect url=\"/target\"/></partial-response>"));
assertEquals("application/xml", jsfMock.response().getContentType());
}