You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ja...@apache.org on 2010/11/26 21:59:18 UTC
svn commit: r1039559 - in /myfaces/extensions/cdi/trunk:
examples/jsf-examples/windowhandler_jsf20/src/main/webapp/WEB-INF/
jee-modules/jsf-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf/impl/scope/conversation/
jee-modules/jsf20-modul...
Author: jakobk
Date: Fri Nov 26 20:59:18 2010
New Revision: 1039559
URL: http://svn.apache.org/viewvc?rev=1039559&view=rev
Log:
EXTCDI-79 change WindowHandlerPhaseListener to ClientSideWindowHandler using new LifecycleAwareWindowHandler SPI (+ added TODOs and removed unused WindowHandlerServlet)
Added:
myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientInformation.java
- copied, changed from r1039532, myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/windowhandler/ClientInformation.java
myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientSideWindowHandler.java
- copied, changed from r1039532, myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientAwareWindowHandler.java
myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/spi/LifecycleAwareWindowHandler.java
Removed:
myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientAwareWindowHandler.java
myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/windowhandler/
Modified:
myfaces/extensions/cdi/trunk/examples/jsf-examples/windowhandler_jsf20/src/main/webapp/WEB-INF/beans.xml
myfaces/extensions/cdi/trunk/jee-modules/jsf-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf/impl/scope/conversation/DefaultWindowHandler.java
myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/listener/phase/CodiLifecycleWrapper.java
Modified: myfaces/extensions/cdi/trunk/examples/jsf-examples/windowhandler_jsf20/src/main/webapp/WEB-INF/beans.xml
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/examples/jsf-examples/windowhandler_jsf20/src/main/webapp/WEB-INF/beans.xml?rev=1039559&r1=1039558&r2=1039559&view=diff
==============================================================================
--- myfaces/extensions/cdi/trunk/examples/jsf-examples/windowhandler_jsf20/src/main/webapp/WEB-INF/beans.xml (original)
+++ myfaces/extensions/cdi/trunk/examples/jsf-examples/windowhandler_jsf20/src/main/webapp/WEB-INF/beans.xml Fri Nov 26 20:59:18 2010
@@ -21,4 +21,8 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+ <alternatives>
+ <class>org.apache.myfaces.extensions.cdi.jsf2.impl.scope.conversation.ClientSideWindowHandler</class>
+ </alternatives>
+
</beans>
\ No newline at end of file
Modified: myfaces/extensions/cdi/trunk/jee-modules/jsf-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf/impl/scope/conversation/DefaultWindowHandler.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/jee-modules/jsf-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf/impl/scope/conversation/DefaultWindowHandler.java?rev=1039559&r1=1039558&r2=1039559&view=diff
==============================================================================
--- myfaces/extensions/cdi/trunk/jee-modules/jsf-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf/impl/scope/conversation/DefaultWindowHandler.java (original)
+++ myfaces/extensions/cdi/trunk/jee-modules/jsf-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf/impl/scope/conversation/DefaultWindowHandler.java Fri Nov 26 20:59:18 2010
@@ -99,6 +99,9 @@ public class DefaultWindowHandler implem
finalUrl.append("&");
finalUrl.append(key);
finalUrl.append("=");
+ // TODO encodeActionURL does NOT correctly encode URL parameter values
+ // see MyFaces ServletExternalContextImpl.encodeURL() for detail!
+ // TODO use ClientSideWindowHandler.encodeURIComponent() instead
finalUrl.append(externalContext.encodeActionURL(requestParam.getValue()));
}
}
Modified: myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/listener/phase/CodiLifecycleWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/listener/phase/CodiLifecycleWrapper.java?rev=1039559&r1=1039558&r2=1039559&view=diff
==============================================================================
--- myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/listener/phase/CodiLifecycleWrapper.java (original)
+++ myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/listener/phase/CodiLifecycleWrapper.java Fri Nov 26 20:59:18 2010
@@ -18,6 +18,10 @@
*/
package org.apache.myfaces.extensions.cdi.jsf2.impl.listener.phase;
+import org.apache.myfaces.extensions.cdi.core.impl.util.CodiUtils;
+import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.spi.WindowHandler;
+import org.apache.myfaces.extensions.cdi.jsf2.impl.scope.conversation.spi.LifecycleAwareWindowHandler;
+
import javax.faces.FacesException;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseListener;
@@ -52,7 +56,16 @@ class CodiLifecycleWrapper extends Lifec
public void execute(FacesContext facesContext)
throws FacesException
{
- // TODO move WindowHandlerPhaseListener invocation here (as early as possible, before any other PhaseListener) ?
+ WindowHandler windowHandler = CodiUtils.getOrCreateScopedInstanceOfBeanByClass(WindowHandler.class, false);
+ if (windowHandler instanceof LifecycleAwareWindowHandler)
+ {
+ ((LifecycleAwareWindowHandler) windowHandler).beforeLifecycleExecute(facesContext);
+ if (facesContext.getResponseComplete())
+ {
+ // no further processing
+ return;
+ }
+ }
wrapped.execute(facesContext);
}
Copied: myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientInformation.java (from r1039532, myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/windowhandler/ClientInformation.java)
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientInformation.java?p2=myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientInformation.java&p1=myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/windowhandler/ClientInformation.java&r1=1039532&r2=1039559&rev=1039559&view=diff
==============================================================================
--- myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/windowhandler/ClientInformation.java (original)
+++ myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientInformation.java Fri Nov 26 20:59:18 2010
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.myfaces.extensions.cdi.jsf2.impl.windowhandler;
+package org.apache.myfaces.extensions.cdi.jsf2.impl.scope.conversation;
import org.apache.myfaces.extensions.cdi.core.api.projectstage.ProjectStage;
import org.apache.myfaces.extensions.cdi.core.api.util.ClassUtils;
Copied: myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientSideWindowHandler.java (from r1039532, myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientAwareWindowHandler.java)
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientSideWindowHandler.java?p2=myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientSideWindowHandler.java&p1=myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientAwareWindowHandler.java&r1=1039532&r2=1039559&rev=1039559&view=diff
==============================================================================
--- myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientAwareWindowHandler.java (original)
+++ myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/ClientSideWindowHandler.java Fri Nov 26 20:59:18 2010
@@ -18,71 +18,252 @@
*/
package org.apache.myfaces.extensions.cdi.jsf2.impl.scope.conversation;
-import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.DefaultWindowHandler;
-import org.apache.myfaces.extensions.cdi.jsf2.impl.windowhandler.Jsf2WindowHandlerServlet;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.config.WindowContextConfig;
+import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.DefaultWindowHandler;
+import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.spi.EditableWindowContext;
+import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.spi.EditableWindowContextManager;
+import org.apache.myfaces.extensions.cdi.jsf2.impl.scope.conversation.spi.LifecycleAwareWindowHandler;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Alternative;
+import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
-import javax.faces.context.PartialViewContext;
import javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import static org.apache.myfaces.extensions.cdi.core.impl.scope.conversation.spi.WindowContextManager
+ .CREATE_NEW_WINDOW_CONTEXT_ID_VALUE;
+import static org.apache.myfaces.extensions.cdi.core.impl.scope.conversation.spi.WindowContextManager
+ .WINDOW_CONTEXT_ID_PARAMETER_KEY;
/**
- * WindowHandler with JSF2 features
+ * WindowHandler which uses JavaScript to store the windowId.
*/
@Alternative
@ApplicationScoped
-public class ClientAwareWindowHandler extends DefaultWindowHandler
+public class ClientSideWindowHandler extends DefaultWindowHandler implements LifecycleAwareWindowHandler
{
private static final long serialVersionUID = 5293942986187078113L;
- protected ClientAwareWindowHandler()
+ private static final String WINDOW_ID_COOKIE_SUFFIX = "-codiWindowId";
+ private static final String UNINITIALIZED_WINDOW_ID_VALUE = "uninitializedWindowId";
+ private static final String WINDOW_ID_REPLACE_PATTERN = "$$windowIdValue$$";
+
+ @Inject
+ private ClientInformation clientInformation;
+
+ @Inject
+ private EditableWindowContextManager windowContextManager;
+
+ protected ClientSideWindowHandler()
{
- // default ct is needed for proxying
+ // needed for proxying
}
@Inject
- protected ClientAwareWindowHandler(WindowContextConfig config)
+ protected ClientSideWindowHandler(WindowContextConfig config)
{
super(config);
}
@Override
- public void sendRedirect(ExternalContext externalContext, String url, boolean addRequestParameter)
- throws IOException
+ public String encodeURL(String url)
{
- PartialViewContext partialViewContext = FacesContext.getCurrentInstance().getPartialViewContext();
+ // do NOT add the windowId to the URL in any case
+ // TODO what if javascript is disabled? fallback to default algorithm?
+ return url;
+ }
- if (partialViewContext != null && partialViewContext.isPartialRequest())
+ @Override
+ public String restoreWindowId(ExternalContext externalContext)
+ {
+ return null;
+ }
+
+ public void beforeLifecycleExecute(FacesContext facesContext)
+ {
+ if (!shouldHandleRequest(facesContext))
{
- super.sendRedirect(externalContext, url, addRequestParameter);
return;
}
- if (url != null && url.startsWith(Jsf2WindowHandlerServlet.WINDOWHANDLER_URL))
+ ExternalContext externalContext = facesContext.getExternalContext();
+
+ String windowId = getWindowIdFromCookie(externalContext);
+ if (windowId == null)
{
- externalContext.redirect(url);
- return;
+ // GET request without windowId - send windowhandlerfilter.html
+ sendWindowHandlerHtml(externalContext, null);
+ facesContext.responseComplete();
+ }
+ else
+ {
+ if (CREATE_NEW_WINDOW_CONTEXT_ID_VALUE.equals(windowId) || !isWindowIdAlive(windowId))
+ {
+ // no or invalid windowId --> create new one
+ windowId = windowContextManager.getCurrentWindowContext().getId();
+
+ // GET request with NEW windowId - send windowhandlerfilter.html
+ sendWindowHandlerHtml(externalContext, windowId);
+ facesContext.responseComplete();
+ }
+ else
+ {
+ // we have a valid windowId - set it and continue with the request
+
+ //X TODO find better way to provide the windowId, because this approach assumes
+ // that the windowId will be cached on the RequestMap and the cache is the only
+ // point to get it #HACK
+ externalContext.getRequestMap().put(WINDOW_CONTEXT_ID_PARAMETER_KEY, windowId);
+ }
+ }
+ }
+
+ private boolean shouldHandleRequest(FacesContext facesContext)
+ {
+ // no POST request and javascript enabled
+ // NOTE that for POST-requests the windowId is saved in the state (see WindowContextIdHolderComponent)
+ return !facesContext.isPostback() && clientInformation.isJavaScriptEnabled();
+ }
+
+ private void sendWindowHandlerHtml(ExternalContext externalContext, String windowId)
+ {
+ HttpServletResponse httpResponse = (HttpServletResponse) externalContext.getResponse();
+
+ try
+ {
+ httpResponse.setStatus(HttpServletResponse.SC_OK);
+ httpResponse.setContentType("text/html");
+
+ String windowHandlerHtml = clientInformation.getWindowHandlerHtml();
+
+ if (windowId == null)
+ {
+ windowId = UNINITIALIZED_WINDOW_ID_VALUE;
+ }
+
+ // set the windowId value in the javascript code
+ windowHandlerHtml = windowHandlerHtml.replace(WINDOW_ID_REPLACE_PATTERN, windowId);
+
+ OutputStream os = httpResponse.getOutputStream();
+ try
+ {
+ os.write(windowHandlerHtml.getBytes());
+ }
+ finally
+ {
+ os.close();
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new FacesException(ioe);
+ }
+ }
+
+ private String getWindowIdFromCookie(ExternalContext externalContext)
+ {
+ String cookieName = getEncodedPathName(externalContext) + WINDOW_ID_COOKIE_SUFFIX;
+ Cookie cookie = (Cookie) externalContext.getRequestCookieMap().get(cookieName);
+
+ if (cookie == null)
+ {
+ // if the current request went to a welcome page, we should only consider the contextPath
+ cookieName = getEncodedContextPath(externalContext) + WINDOW_ID_COOKIE_SUFFIX;
+ cookie = (Cookie) externalContext.getRequestCookieMap().get(cookieName);
}
- super.sendRedirect(externalContext, url, addRequestParameter);
+ if (cookie != null)
+ {
+ return cookie.getValue();
+ }
+
+ return null;
}
- private String getWindowHandlerPath(ExternalContext externalContext)
+ private String getEncodedPathName(ExternalContext externalContext)
{
+ StringBuilder sb = new StringBuilder();
+
String contextPath = externalContext.getRequestContextPath();
+ if (contextPath != null)
+ {
+ sb.append(contextPath);
+ }
- if (contextPath == null)
+ String servletPath = externalContext.getRequestServletPath();
+ if (servletPath != null)
{
- return Jsf2WindowHandlerServlet.WINDOWHANDLER_URL;
+ sb.append(servletPath);
}
- else
+
+ String pathInfo = externalContext.getRequestPathInfo();
+ if (pathInfo != null)
+ {
+ sb.append(pathInfo);
+ }
+
+ // remove all "/", because they can be different in JavaScript
+ String pathName = sb.toString().replace("/", "");
+
+ return encodeURIComponent(pathName, externalContext);
+ }
+
+ private String getEncodedContextPath(ExternalContext externalContext)
+ {
+ String contextPath = externalContext.getRequestContextPath();
+ if (contextPath != null)
+ {
+ // remove all "/", because they can be different in JavaScript
+ contextPath = contextPath.replace("/", "");
+
+ return encodeURIComponent(contextPath, externalContext);
+ }
+
+ return "";
+ }
+
+ /**
+ * JavaScript equivalent method.
+ *
+ * This is how the ExternalContext impl encodes URL parameter values.
+ *
+ * TODO move to Utils class - also needed in DefaultWindowHandler
+ *
+ * @param component
+ * @param externalContext
+ * @return
+ */
+ private String encodeURIComponent(String component, ExternalContext externalContext)
+ {
+ try
{
- return contextPath + Jsf2WindowHandlerServlet.WINDOWHANDLER_URL;
+ return URLEncoder.encode(component, externalContext.getResponseCharacterEncoding());
}
+ catch (UnsupportedEncodingException e)
+ {
+ throw new UnsupportedOperationException("Encoding type="
+ + externalContext.getResponseCharacterEncoding() + " not supported", e);
+ }
+ }
+
+ private boolean isWindowIdAlive(String windowId)
+ {
+ for (EditableWindowContext wc : windowContextManager.getWindowContexts())
+ {
+ if (windowId.equals(wc.getId()))
+ {
+ return true;
+ }
+ }
+
+ return false;
}
}
Added: myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/spi/LifecycleAwareWindowHandler.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/spi/LifecycleAwareWindowHandler.java?rev=1039559&view=auto
==============================================================================
--- myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/spi/LifecycleAwareWindowHandler.java (added)
+++ myfaces/extensions/cdi/trunk/jee-modules/jsf20-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jsf2/impl/scope/conversation/spi/LifecycleAwareWindowHandler.java Fri Nov 26 20:59:18 2010
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.myfaces.extensions.cdi.jsf2.impl.scope.conversation.spi;
+
+import org.apache.myfaces.extensions.cdi.jsf.impl.scope.conversation.spi.WindowHandler;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * A WindowHandler that is aware of the JSF lifecycle.
+ *
+ * @author Jakob Korherr
+ */
+public interface LifecycleAwareWindowHandler extends WindowHandler
+{
+
+ /**
+ * Is called before the execute portion of the JSF lifecycle starts.
+ * If this method sets responseComplete() to true, the lifecycle won't be started.
+ *
+ * @param facesContext
+ */
+ void beforeLifecycleExecute(FacesContext facesContext);
+
+}
\ No newline at end of file