You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by ta...@apache.org on 2015/06/29 20:57:14 UTC

[2/2] deltaspike git commit: DELTASPIKE-932 moved modes to own classes

DELTASPIKE-932 moved modes to own classes

Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/ff4c502f
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/ff4c502f
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/ff4c502f

Branch: refs/heads/master
Commit: ff4c502f23ae36143923e00cea7c6e57da8a97f5
Parents: 99a8804
Author: Thomas Andraschko <ta...@apache.org>
Authored: Mon Jun 29 20:57:04 2015 +0200
Committer: Thomas Andraschko <ta...@apache.org>
Committed: Mon Jun 29 20:57:04 2015 +0200

----------------------------------------------------------------------
 .../impl/scope/window/DefaultClientWindow.java  | 403 ++-----------------
 .../strategy/AbstractClientWindowStrategy.java  | 195 +++++++++
 .../strategy/ClientSideWindowStrategy.java      | 198 +++++++++
 .../strategy/DelegatedWindowStrategy.java       |  47 +++
 .../window/strategy/LazyWindowStrategy.java     |  89 ++++
 .../window/strategy/NoneWindowStrategy.java     |  35 ++
 .../jsf/impl/util/ClientWindowHelper.java       | 377 ++++++++---------
 7 files changed, 793 insertions(+), 551 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ff4c502f/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
index c6f4932..2db4b7e 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
@@ -18,28 +18,17 @@
  */
 package org.apache.deltaspike.jsf.impl.scope.window;
 
-import org.apache.deltaspike.core.spi.scope.window.WindowContext;
-import org.apache.deltaspike.jsf.api.config.JsfModuleConfig;
-import org.apache.deltaspike.jsf.impl.util.ClientWindowHelper;
-import org.apache.deltaspike.jsf.impl.util.JsfUtils;
 import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow;
 import org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig;
 
-import javax.annotation.PostConstruct;
 import javax.enterprise.context.ApplicationScoped;
-import javax.faces.FacesException;
-import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.inject.Inject;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.HashMap;
 import java.util.Map;
-import java.util.Random;
-import javax.servlet.http.HttpServletRequest;
-import org.apache.deltaspike.core.util.StringUtils;
+import org.apache.deltaspike.jsf.impl.scope.window.strategy.ClientSideWindowStrategy;
+import org.apache.deltaspike.jsf.impl.scope.window.strategy.DelegatedWindowStrategy;
+import org.apache.deltaspike.jsf.impl.scope.window.strategy.LazyWindowStrategy;
+import org.apache.deltaspike.jsf.impl.scope.window.strategy.NoneWindowStrategy;
 
 import static org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig.ClientWindowRenderMode;
 
@@ -54,395 +43,69 @@ import static org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig.Clie
 @ApplicationScoped
 public class DefaultClientWindow implements ClientWindow
 {
-    /**
-     * Value which can be used as "window-id" by external clients which aren't aware of windows.
-     * It deactivates e.g. the redirect for the initial request.
-     */
-    public static final String AUTOMATED_ENTRY_POINT_PARAMETER_KEY = "automatedEntryPoint";
-
-    /**
-     * The parameter for the windowId for POST requests
-     */
-    public static final String DELTASPIKE_WINDOW_ID_POST_PARAM = "dspwid";
-    public static final String JSF_WINDOW_ID_POST_PARAM = "javax.faces.ClientWindow";
-
-    /**
-     * GET request parameter
-     */
-    public static final String DELTASPIKE_WINDOW_ID_URL_PARAM = "dswid";
-
-    private static final String PER_USE_CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED_KEY =
-            ClientWindow.class.getName() + ".ClientWindowRenderModeEnablement";
-
-    private static final String WINDOW_ID_COOKIE_PREFIX = "dsWindowId-";
-    private static final String DELTASPIKE_REQUEST_TOKEN = "dsrid";
-
-    private static final String UNINITIALIZED_WINDOW_ID_VALUE = "uninitializedWindowId";
-    private static final String WINDOW_ID_REPLACE_PATTERN = "$$windowIdValue$$";
-    private static final String NOSCRIPT_URL_REPLACE_PATTERN = "$$noscriptUrl$$";
-
-    /**
-     * Use this parameter to force a 'direct' request from the clients without any windowId detection
-     * We keep this name for backward compat with CODI.
-     */
-    private static final String NOSCRIPT_PARAMETER = "mfDirect";
-
-    /**
-     * This windowId will be used for all requests with disabled windowId feature
-     */
-    private static final String DEFAULT_WINDOW_ID = "default";
-
-    private static final String WINDOW_ID_REQUEST_MAP_KEY =
-            ClientWindow.class.getName() + ".WindowId";
-
-    private static final String CACHE_QUERY_URL_PARAMETERS =
-            "CACHE:" + DefaultClientWindow.class + "#getQueryURLParameters";
-
     @Inject
     private ClientWindowConfig clientWindowConfig;
 
     @Inject
-    private JsfModuleConfig jsfModuleConfig;
+    private ClientSideWindowStrategy clientSideWindowStrategy;
 
     @Inject
-    private WindowContext windowContext;
-
-    private int maxWindowIdCount = 10;
+    private DelegatedWindowStrategy delegatedWindowStrategy;
 
+    @Inject
+    private LazyWindowStrategy lazyWindowStrategy;
 
-    @PostConstruct
-    protected void init()
-    {
-        this.maxWindowIdCount = ClientWindowHelper.getMaxWindowIdLength();
-    }
+    @Inject
+    private NoneWindowStrategy noneWindowStrategy;
 
     @Override
     public String getWindowId(FacesContext facesContext)
     {
-        String windowId = getOrCreateWindowId(facesContext);
-
-        if (windowId != null && windowId.length() > this.maxWindowIdCount)
-        {
-            windowId = windowId.substring(0, this.maxWindowIdCount);
-        }
-        return windowId;
-    }
-
-    protected String getOrCreateWindowId(FacesContext facesContext)
-    {
-        ExternalContext externalContext = facesContext.getExternalContext();
-        Map<String, Object> requestMap = externalContext.getRequestMap();
-        
-        // try to lookup from cache
-        String windowId = (String) requestMap.get(WINDOW_ID_REQUEST_MAP_KEY);
-        if (windowId != null)
-        {
-            return windowId;
-        }
-        
-        ClientWindowRenderMode clientWindowRenderMode = clientWindowConfig.getClientWindowRenderMode(facesContext);
-        if (ClientWindowRenderMode.NONE.equals(clientWindowRenderMode))
-        {
-            // if this request should not get any window detection then we are done
-            windowId = DEFAULT_WINDOW_ID;
-        }
-        else if (ClientWindowRenderMode.DELEGATED.equals(clientWindowRenderMode))
-        {
-            windowId = ClientWindowAdapter.getWindowIdFromJsf(facesContext);
-        }
-        else if (ClientWindowRenderMode.LAZY.equals(clientWindowRenderMode))
-        {
-            windowId = ClientWindowHelper.getInitialRedirectWindowId(facesContext);
-
-            if (StringUtils.isEmpty(windowId))
-            {
-                windowId = externalContext.getRequestParameterMap().get(DELTASPIKE_WINDOW_ID_URL_PARAM);
-            }
-
-            boolean post = isPost(facesContext);
-            
-            if (StringUtils.isEmpty(windowId) && post)
-            {
-                windowId = getPostBackWindowId(facesContext);
-            }
-            
-            if (StringUtils.isEmpty(windowId))
-            {
-                if (this.jsfModuleConfig.isInitialRedirectEnabled() && !post)
-                {
-                    ClientWindowHelper.handleInitialRedirect(facesContext, generateNewWindowId());
-                    facesContext.responseComplete();
-                    windowId = null;
-                }
-                else
-                {
-                    windowId = generateNewWindowId();
-                }
-            }
-        }
-        else if (ClientWindowRenderMode.CLIENTWINDOW.equals(clientWindowRenderMode))
-        {
-            boolean post = isPost(facesContext);
-            
-            if (post)
-            {
-                windowId = getPostBackWindowId(facesContext);
-            }
-            else if (isNoscriptRequest(externalContext))
-            {
-                // the client has JavaScript disabled
-                clientWindowConfig.setJavaScriptEnabled(false);
-
-                windowId = DEFAULT_WINDOW_ID;
-            }
-            else
-            {
-                windowId = getVerifiedWindowIdFromCookie(externalContext);
-
-                boolean newWindowIdRequested = false;
-                if (AUTOMATED_ENTRY_POINT_PARAMETER_KEY.equals(windowId))
-                {
-                    // this is a marker for generating a new windowId
-                    windowId = generateNewWindowId();
-                    newWindowIdRequested = true;
-                }
-
-                if (windowId == null || newWindowIdRequested)
-                {
-                    // GET request without windowId - send windowhandlerfilter.html to get the windowId
-                    sendWindowHandlerHtml(externalContext, windowId);
-                    facesContext.responseComplete();
-                }
-            }
-        }
-
-        // we have a valid windowId - set it and continue with the request
-        if (windowId != null)
-        {
-            requestMap.put(WINDOW_ID_REQUEST_MAP_KEY, windowId);
-        }
-        
-        return windowId;
-    }
-
-    /**
-     * Create a unique windowId
-     * @return
-     */
-    private String generateNewWindowId()
-    {
-        //X TODO proper mechanism
-        return "" + (new Random()).nextInt() % 10000;
-    }
-
-    private boolean isPost(FacesContext context)
-    {
-        if (context.isPostback())
-        {
-            return true;
-        }
-        
-        Object request = context.getExternalContext().getRequest();
-        if (request instanceof HttpServletRequest)
-        {
-            if ("POST".equals(((HttpServletRequest) request).getMethod()))
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-    
-    /**
-     * Extract the windowId for http POST
-     */
-    private String getPostBackWindowId(FacesContext facesContext)
-    {
-        Map<String, String> requestParams = facesContext.getExternalContext().getRequestParameterMap();
-        String windowId = requestParams.get(DELTASPIKE_WINDOW_ID_POST_PARAM);
-
-        if (windowId == null)
-        {
-            windowId = requestParams.get(JSF_WINDOW_ID_POST_PARAM);
-        }
-        return windowId;
-    }
-
-    private boolean isNoscriptRequest(ExternalContext externalContext)
-    {
-        String noscript = externalContext.getRequestParameterMap().get(NOSCRIPT_PARAMETER);
-
-        return (noscript != null && "true".equals(noscript));
-    }
-
-    private void sendWindowHandlerHtml(ExternalContext externalContext, String windowId)
-    {
-        HttpServletResponse httpResponse = (HttpServletResponse) externalContext.getResponse();
-
-        try
-        {
-            httpResponse.setStatus(HttpServletResponse.SC_OK);
-            httpResponse.setContentType("text/html");
-
-            String windowHandlerHtml = clientWindowConfig.getClientWindowHtml();
-
-            if (windowId == null)
-            {
-                windowId = UNINITIALIZED_WINDOW_ID_VALUE;
-            }
-
-            // set the windowId value in the javascript code
-            windowHandlerHtml = windowHandlerHtml.replace(WINDOW_ID_REPLACE_PATTERN, windowId);
-
-            // set the noscript-URL for users with no JavaScript
-            windowHandlerHtml =
-                    windowHandlerHtml.replace(NOSCRIPT_URL_REPLACE_PATTERN, getNoscriptUrl(externalContext));
-
-            OutputStream os = httpResponse.getOutputStream();
-            try
-            {
-                os.write(windowHandlerHtml.getBytes());
-            }
-            finally
-            {
-                os.close();
-            }
-        }
-        catch (IOException ioe)
-        {
-            throw new FacesException(ioe);
-        }
-    }
-
-    private String getNoscriptUrl(ExternalContext externalContext)
-    {
-        String url = externalContext.getRequestPathInfo();
-        if (url == null)
-        {
-            url = "";
-        }
-
-        // only use the very last part of the url
-        int lastSlash = url.lastIndexOf('/');
-        if (lastSlash != -1)
-        {
-            url = url.substring(lastSlash + 1);
-        }
-
-        // add request parameter
-        url = JsfUtils.addPageParameters(externalContext, url, true);
-        url = JsfUtils.addParameter(externalContext, url, false, NOSCRIPT_PARAMETER, "true");
-
-        // NOTE that the url could contain data for an XSS attack
-        // like e.g. ?"></a><a href%3D"http://hacker.org/attack.html?a
-        // DO NOT REMOVE THE FOLLOWING LINES!
-        url = url.replace("\"", "");
-        url = url.replace("\'", "");
-
-        return url;
-    }
-
-    private String getVerifiedWindowIdFromCookie(ExternalContext externalContext)
-    {
-        String cookieName = WINDOW_ID_COOKIE_PREFIX + getRequestToken(externalContext);
-        Cookie cookie = (Cookie) externalContext.getRequestCookieMap().get(cookieName);
-
-        if (cookie != null)
-        {
-            // manually blast the cookie away, otherwise it pollutes the
-            // cookie storage in some browsers. E.g. Firefox doesn't
-            // cleanup properly, even if the max-age is reached.
-            cookie.setMaxAge(0);
-
-            return cookie.getValue();
-        }
-
-        return null;
-    }
-
-    private String getRequestToken(ExternalContext externalContext)
-    {
-        String requestToken = externalContext.getRequestParameterMap().get(DELTASPIKE_REQUEST_TOKEN);
-        if (requestToken != null)
-        {
-            return requestToken;
-        }
-
-        return "";
+        return getClientWindow(facesContext).getWindowId(facesContext);
     }
 
     @Override
     public void disableClientWindowRenderMode(FacesContext facesContext)
     {
-        ClientWindowRenderMode clientWindowRenderMode = clientWindowConfig.getClientWindowRenderMode(facesContext);
-
-        if (ClientWindowRenderMode.DELEGATED.equals(clientWindowRenderMode))
-        {
-            facesContext.getExternalContext().getClientWindow().disableClientWindowRenderMode(facesContext);
-        }
-        else if (ClientWindowRenderMode.LAZY.equals(clientWindowRenderMode))
-        {
-            Map<Object, Object> attrMap = facesContext.getAttributes();
-            attrMap.put(PER_USE_CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED_KEY, Boolean.TRUE);
-        }
+        getClientWindow(facesContext).disableClientWindowRenderMode(facesContext);
     }
 
     @Override
     public void enableClientWindowRenderMode(FacesContext facesContext)
     {
-        ClientWindowRenderMode clientWindowRenderMode = clientWindowConfig.getClientWindowRenderMode(facesContext);
-
-        if (ClientWindowRenderMode.DELEGATED.equals(clientWindowRenderMode))
-        {
-            facesContext.getExternalContext().getClientWindow().enableClientWindowRenderMode(facesContext);
-        }
-        else if (ClientWindowRenderMode.LAZY.equals(clientWindowRenderMode))
-        {
-            Map<Object, Object> attrMap = facesContext.getAttributes();
-            attrMap.remove(PER_USE_CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED_KEY);
-        }
+        getClientWindow(facesContext).enableClientWindowRenderMode(facesContext);
     }
 
     @Override
     public boolean isClientWindowRenderModeEnabled(FacesContext facesContext)
     {
-        ClientWindowRenderMode clientWindowRenderMode = clientWindowConfig.getClientWindowRenderMode(facesContext);
-
-        if (ClientWindowRenderMode.LAZY.equals(clientWindowRenderMode))
-        {
-            Map<Object, Object> attrMap = facesContext.getAttributes();
-            return  !attrMap.containsKey(PER_USE_CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED_KEY);
-        }
-
-        return false;
+        return getClientWindow(facesContext).isClientWindowRenderModeEnabled(facesContext);
     }
 
     @Override
     public Map<String, String> getQueryURLParameters(FacesContext facesContext)
     {
-        ClientWindowRenderMode clientWindowRenderMode = clientWindowConfig.getClientWindowRenderMode(facesContext);
-
-        if (ClientWindowRenderMode.LAZY.equals(clientWindowRenderMode))
-        {
-            if (!facesContext.getAttributes().containsKey(CACHE_QUERY_URL_PARAMETERS))
-            {
-                String windowId = getWindowId(facesContext);
-                
-                if (windowId == null)
-                {
-                    return null;
-                }
-                
-                Map<String, String> params = new HashMap<String, String>();
-                params.put(DELTASPIKE_WINDOW_ID_URL_PARAM, windowId);
+        return getClientWindow(facesContext).getQueryURLParameters(facesContext);
+    }
 
-                facesContext.getAttributes().put(CACHE_QUERY_URL_PARAMETERS, params);
-            }
+    protected ClientWindow getClientWindow(FacesContext facesContext)
+    {
+        ClientWindowRenderMode clientWindowRenderMode = clientWindowConfig.getClientWindowRenderMode(facesContext);
 
-            return (Map<String, String>) facesContext.getAttributes().get(CACHE_QUERY_URL_PARAMETERS);
+        switch (clientWindowRenderMode)
+        {
+            case CLIENTWINDOW:
+                return clientSideWindowStrategy;
+            case CUSTOM:
+                return null;
+            case DELEGATED:
+                return delegatedWindowStrategy;
+            case LAZY:
+                return lazyWindowStrategy;
+            case NONE:
+                return noneWindowStrategy;
+            default:
+                return null;
         }
-
-        return null;
     }
 }

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ff4c502f/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/AbstractClientWindowStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/AbstractClientWindowStrategy.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/AbstractClientWindowStrategy.java
new file mode 100644
index 0000000..a985630
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/AbstractClientWindowStrategy.java
@@ -0,0 +1,195 @@
+/*
+ * 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.deltaspike.jsf.impl.scope.window.strategy;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Random;
+import javax.annotation.PostConstruct;
+import javax.faces.context.FacesContext;
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.deltaspike.core.spi.scope.window.WindowContext;
+import org.apache.deltaspike.jsf.api.config.JsfModuleConfig;
+import org.apache.deltaspike.jsf.impl.util.ClientWindowHelper;
+import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow;
+import org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig;
+
+public abstract class AbstractClientWindowStrategy implements ClientWindow
+{
+    /**
+     * This windowId will be used for all requests with disabled windowId feature
+     */
+    public static final String DEFAULT_WINDOW_ID = "default";
+
+    private static final String CACHE_QUERY_URL_PARAMETERS =
+            "CACHE:" + AbstractClientWindowStrategy.class.getName() + "#getQueryURLParameters";
+    private static final String CACHE_WINDOW_ID =
+            "CACHE:" + AbstractClientWindowStrategy.class.getName() + ".WindowId";
+
+    private static final String PER_USE_CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED_KEY =
+            LazyWindowStrategy.class.getName() + ".ClientWindowRenderModeEnablement";
+
+    @Inject
+    protected ClientWindowConfig clientWindowConfig;
+
+    @Inject
+    protected JsfModuleConfig jsfModuleConfig;
+
+    @Inject
+    protected WindowContext windowContext;
+
+    private int maxWindowIdCount = 10;
+
+    @PostConstruct
+    protected void init()
+    {
+        this.maxWindowIdCount = ClientWindowHelper.getMaxWindowIdLength();
+    }
+
+
+    @Override
+    public String getWindowId(FacesContext facesContext)
+    {
+        Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
+
+        // try to lookup from cache
+        String windowId = (String) requestMap.get(CACHE_WINDOW_ID);
+        if (windowId != null)
+        {
+            return windowId;
+        }
+
+        windowId = getOrCreateWindowId(facesContext);
+
+        if (windowId != null && windowId.length() > this.maxWindowIdCount)
+        {
+            windowId = windowId.substring(0, this.maxWindowIdCount);
+
+            requestMap.put(CACHE_WINDOW_ID, windowId);
+        }
+
+        return windowId;
+    }
+
+    protected abstract String getOrCreateWindowId(FacesContext facesContext);
+
+    protected String generateNewWindowId()
+    {
+        //X TODO proper mechanism
+        return "" + (new Random()).nextInt() % 10000;
+    }
+
+    protected boolean isPost(FacesContext facesContext)
+    {
+        if (facesContext.isPostback())
+        {
+            return true;
+        }
+
+        Object request = facesContext.getExternalContext().getRequest();
+        if (request instanceof HttpServletRequest)
+        {
+            if ("POST".equals(((HttpServletRequest) request).getMethod()))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Extract the windowId for http POST
+     */
+    protected String getPostBackWindowId(FacesContext facesContext)
+    {
+        Map<String, String> requestParams = facesContext.getExternalContext().getRequestParameterMap();
+        String windowId = requestParams.get(ClientWindowHelper.RequestParameters.POST_WINDOW_ID);
+
+        if (windowId == null)
+        {
+            windowId = requestParams.get(ClientWindowHelper.RequestParameters.JSF_POST_WINDOW_ID);
+        }
+        return windowId;
+    }
+
+    @Override
+    public void disableClientWindowRenderMode(FacesContext facesContext)
+    {
+        if (isSupportClientWindowRenderingMode())
+        {
+            Map<Object, Object> attrMap = facesContext.getAttributes();
+            attrMap.put(PER_USE_CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED_KEY, Boolean.TRUE);
+        }
+    }
+
+    @Override
+    public void enableClientWindowRenderMode(FacesContext facesContext)
+    {
+        if (isSupportClientWindowRenderingMode())
+        {
+            Map<Object, Object> attrMap = facesContext.getAttributes();
+            attrMap.remove(PER_USE_CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED_KEY);
+        }
+    }
+
+    @Override
+    public boolean isClientWindowRenderModeEnabled(FacesContext facesContext)
+    {
+        if (isSupportClientWindowRenderingMode())
+        {
+            Map<Object, Object> attrMap = facesContext.getAttributes();
+            return !attrMap.containsKey(PER_USE_CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED_KEY);
+        }
+
+        return false;
+    }
+
+    protected boolean isSupportClientWindowRenderingMode()
+    {
+        return false;
+    }
+
+    @Override
+    public Map<String, String> getQueryURLParameters(FacesContext facesContext)
+    {
+        Map<String, String> cachedParameters =
+                (Map<String, String>) facesContext.getAttributes().get(CACHE_QUERY_URL_PARAMETERS);
+
+        // cache paramters per request - will be called many times
+        if (cachedParameters == null)
+        {
+            cachedParameters = createQueryURLParameters(facesContext);
+            if (cachedParameters == null)
+            {
+                cachedParameters = Collections.EMPTY_MAP;
+            }
+
+            facesContext.getAttributes().put(CACHE_QUERY_URL_PARAMETERS, cachedParameters);
+        }
+
+        return cachedParameters;
+    }
+
+    protected Map<String, String> createQueryURLParameters(FacesContext facesContext)
+    {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ff4c502f/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/ClientSideWindowStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/ClientSideWindowStrategy.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/ClientSideWindowStrategy.java
new file mode 100644
index 0000000..fdf2ee9
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/ClientSideWindowStrategy.java
@@ -0,0 +1,198 @@
+/*
+ * 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.deltaspike.jsf.impl.scope.window.strategy;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Typed;
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.deltaspike.jsf.impl.util.ClientWindowHelper;
+import org.apache.deltaspike.jsf.impl.util.JsfUtils;
+
+@Dependent
+@Typed(ClientSideWindowStrategy.class)
+public class ClientSideWindowStrategy extends AbstractClientWindowStrategy
+{
+    /**
+     * Value which can be used as "window-id" by external clients which aren't aware of windows.
+     * It deactivates e.g. the redirect for the initial request.
+     */
+    private static final String AUTOMATED_ENTRY_POINT_PARAMETER_KEY = "automatedEntryPoint";
+
+    private static final String UNINITIALIZED_WINDOW_ID_VALUE = "uninitializedWindowId";
+    private static final String WINDOW_ID_REPLACE_PATTERN = "$$windowIdValue$$";
+    private static final String NOSCRIPT_URL_REPLACE_PATTERN = "$$noscriptUrl$$";
+
+    /**
+     * Use this parameter to force a 'direct' request from the clients without any windowId detection
+     * We keep this name for backward compat with CODI.
+     */
+    private static final String NOSCRIPT_PARAMETER = "mfDirect";
+
+
+    @Override
+    protected String getOrCreateWindowId(FacesContext facesContext)
+    {
+        String windowId = null;
+
+        boolean post = isPost(facesContext);
+
+        if (post)
+        {
+            windowId = getPostBackWindowId(facesContext);
+        }
+        else if (isNoscriptRequest(facesContext.getExternalContext()))
+        {
+            // the client has JavaScript disabled
+            clientWindowConfig.setJavaScriptEnabled(false);
+
+            windowId = DEFAULT_WINDOW_ID;
+        }
+        else
+        {
+            windowId = getVerifiedWindowIdFromCookie(facesContext.getExternalContext());
+
+            boolean newWindowIdRequested = false;
+            if (AUTOMATED_ENTRY_POINT_PARAMETER_KEY.equals(windowId))
+            {
+                // this is a marker for generating a new windowId
+                windowId = generateNewWindowId();
+                newWindowIdRequested = true;
+            }
+
+            if (windowId == null || newWindowIdRequested)
+            {
+                // GET request without windowId - send windowhandlerfilter.html to get the windowId
+                sendWindowHandlerHtml(facesContext.getExternalContext(), windowId);
+                facesContext.responseComplete();
+            }
+        }
+
+        return windowId;
+    }
+
+    protected boolean isNoscriptRequest(ExternalContext externalContext)
+    {
+        String noscript = externalContext.getRequestParameterMap().get(NOSCRIPT_PARAMETER);
+
+        return (noscript != null && "true".equals(noscript));
+    }
+
+    protected void sendWindowHandlerHtml(ExternalContext externalContext, String windowId)
+    {
+        HttpServletResponse httpResponse = (HttpServletResponse) externalContext.getResponse();
+
+        try
+        {
+            httpResponse.setStatus(HttpServletResponse.SC_OK);
+            httpResponse.setContentType("text/html");
+
+            String windowHandlerHtml = clientWindowConfig.getClientWindowHtml();
+
+            if (windowId == null)
+            {
+                windowId = UNINITIALIZED_WINDOW_ID_VALUE;
+            }
+
+            // set the windowId value in the javascript code
+            windowHandlerHtml = windowHandlerHtml.replace(WINDOW_ID_REPLACE_PATTERN, windowId);
+
+            // set the noscript-URL for users with no JavaScript
+            windowHandlerHtml =
+                    windowHandlerHtml.replace(NOSCRIPT_URL_REPLACE_PATTERN, getNoscriptUrl(externalContext));
+
+            OutputStream os = httpResponse.getOutputStream();
+            try
+            {
+                os.write(windowHandlerHtml.getBytes());
+            }
+            finally
+            {
+                os.close();
+            }
+        }
+        catch (IOException ioe)
+        {
+            throw new FacesException(ioe);
+        }
+    }
+
+    protected String getNoscriptUrl(ExternalContext externalContext)
+    {
+        String url = externalContext.getRequestPathInfo();
+        if (url == null)
+        {
+            url = "";
+        }
+
+        // only use the very last part of the url
+        int lastSlash = url.lastIndexOf('/');
+        if (lastSlash != -1)
+        {
+            url = url.substring(lastSlash + 1);
+        }
+
+        // add request parameter
+        url = JsfUtils.addPageParameters(externalContext, url, true);
+        url = JsfUtils.addParameter(externalContext, url, false, NOSCRIPT_PARAMETER, "true");
+
+        // NOTE that the url could contain data for an XSS attack
+        // like e.g. ?"></a><a href%3D"http://hacker.org/attack.html?a
+        // DO NOT REMOVE THE FOLLOWING LINES!
+        url = url.replace("\"", "");
+        url = url.replace("\'", "");
+
+        return url;
+    }
+
+    protected String getVerifiedWindowIdFromCookie(ExternalContext externalContext)
+    {
+        String cookieName = ClientWindowHelper.Cookies.WINDOW_ID_PREFIX + getRequestToken(externalContext);
+        Cookie cookie = (Cookie) externalContext.getRequestCookieMap().get(cookieName);
+
+        if (cookie != null)
+        {
+            // manually blast the cookie away, otherwise it pollutes the
+            // cookie storage in some browsers. E.g. Firefox doesn't
+            // cleanup properly, even if the max-age is reached.
+            cookie.setMaxAge(0);
+
+            return cookie.getValue();
+        }
+
+        return null;
+    }
+
+    protected String getRequestToken(ExternalContext externalContext)
+    {
+        String requestToken =
+                externalContext.getRequestParameterMap().get(ClientWindowHelper.RequestParameters.REQUEST_TOKEN);
+        if (requestToken != null)
+        {
+            return requestToken;
+        }
+
+        return "";
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ff4c502f/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/DelegatedWindowStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/DelegatedWindowStrategy.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/DelegatedWindowStrategy.java
new file mode 100644
index 0000000..fd12e49
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/DelegatedWindowStrategy.java
@@ -0,0 +1,47 @@
+/*
+ * 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.deltaspike.jsf.impl.scope.window.strategy;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Typed;
+import javax.faces.context.FacesContext;
+import org.apache.deltaspike.jsf.impl.scope.window.ClientWindowAdapter;
+
+@Dependent
+@Typed(DelegatedWindowStrategy.class)
+public class DelegatedWindowStrategy extends AbstractClientWindowStrategy
+{
+    @Override
+    protected String getOrCreateWindowId(FacesContext facesContext)
+    {
+        return ClientWindowAdapter.getWindowIdFromJsf(facesContext);
+    }
+
+    @Override
+    public void disableClientWindowRenderMode(FacesContext facesContext)
+    {
+        facesContext.getExternalContext().getClientWindow().disableClientWindowRenderMode(facesContext);
+    }
+
+    @Override
+    public void enableClientWindowRenderMode(FacesContext facesContext)
+    {
+        facesContext.getExternalContext().getClientWindow().enableClientWindowRenderMode(facesContext);
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ff4c502f/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/LazyWindowStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/LazyWindowStrategy.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/LazyWindowStrategy.java
new file mode 100644
index 0000000..c1ae6ca
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/LazyWindowStrategy.java
@@ -0,0 +1,89 @@
+/*
+ * 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.deltaspike.jsf.impl.scope.window.strategy;
+
+import org.apache.deltaspike.jsf.impl.util.ClientWindowHelper;
+
+import javax.faces.context.FacesContext;
+import java.util.HashMap;
+import java.util.Map;
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Typed;
+import org.apache.deltaspike.core.util.StringUtils;
+
+@Dependent
+@Typed(LazyWindowStrategy.class)
+public class LazyWindowStrategy extends AbstractClientWindowStrategy
+{
+    @Override
+    protected String getOrCreateWindowId(FacesContext facesContext)
+    {
+        String windowId = ClientWindowHelper.getInitialRedirectWindowId(facesContext);
+
+        if (StringUtils.isEmpty(windowId))
+        {
+            Map<String, String> requestParameters = facesContext.getExternalContext().getRequestParameterMap();
+            windowId = requestParameters.get(ClientWindowHelper.RequestParameters.GET_WINDOW_ID);
+        }
+
+        boolean post = isPost(facesContext);
+
+        if (StringUtils.isEmpty(windowId) && post)
+        {
+            windowId = getPostBackWindowId(facesContext);
+        }
+
+        if (StringUtils.isEmpty(windowId))
+        {
+            if (jsfModuleConfig.isInitialRedirectEnabled() && !post)
+            {
+                ClientWindowHelper.handleInitialRedirect(facesContext, generateNewWindowId());
+                facesContext.responseComplete();
+                windowId = null;
+            }
+            else
+            {
+                windowId = generateNewWindowId();
+            }
+        }
+
+        return windowId;
+    }
+
+    @Override
+    protected boolean isSupportClientWindowRenderingMode()
+    {
+        return true;
+    }
+
+    @Override
+    protected Map<String, String> createQueryURLParameters(FacesContext facesContext)
+    {
+        String windowId = getWindowId(facesContext);
+
+        if (windowId == null)
+        {
+            return null;
+        }
+
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put(ClientWindowHelper.RequestParameters.GET_WINDOW_ID, windowId);
+        return parameters;
+    }
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ff4c502f/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/NoneWindowStrategy.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/NoneWindowStrategy.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/NoneWindowStrategy.java
new file mode 100644
index 0000000..225c927
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/strategy/NoneWindowStrategy.java
@@ -0,0 +1,35 @@
+/*
+ * 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.deltaspike.jsf.impl.scope.window.strategy;
+
+import javax.enterprise.context.Dependent;
+import javax.enterprise.inject.Typed;
+import javax.faces.context.FacesContext;
+
+@Dependent
+@Typed(NoneWindowStrategy.class)
+public class NoneWindowStrategy extends AbstractClientWindowStrategy
+{
+    @Override
+    protected String getOrCreateWindowId(FacesContext facesContext)
+    {
+        return DEFAULT_WINDOW_ID;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ff4c502f/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java
index 30cf6f0..c86a9b3 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java
@@ -1,181 +1,196 @@
-/*
- * 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.deltaspike.jsf.impl.util;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import javax.enterprise.inject.Typed;
-import javax.faces.FacesException;
-import javax.faces.context.ExternalContext;
-import javax.faces.context.FacesContext;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.deltaspike.jsf.api.config.base.JsfBaseConfig;
-import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow;
-
-@Typed()
-public abstract class ClientWindowHelper
-{
-    public static final String INITIAL_REDIRECT_WINDOW_ID = ClientWindowHelper.class.getName()
-            + ".INITIAL_REDIRECT_WINDOW_ID";
-    public static final String REQUEST_WINDOW_ID_COOKIE_PREFIX = "dsrwid-";
-
-    private static final Logger LOG = Logger.getLogger(ClientWindowHelper.class.getName());
-
-    /**
-     * Handles the initial redirect for the URL modus, if no windowId is available in the current request URL.
-     *
-     * @param facesContext the {@link FacesContext}
-     * @param newWindowId the new windowId
-     */
-    public static void handleInitialRedirect(FacesContext facesContext, String newWindowId)
-    {
-        // store the new windowId as context attribute to prevent infinite loops
-        // #sendRedirect will append the windowId (from ClientWindow#getWindowId again) to the redirectUrl
-        facesContext.getAttributes().put(INITIAL_REDIRECT_WINDOW_ID, newWindowId);
-
-        ExternalContext externalContext = facesContext.getExternalContext();
-
-        String url = externalContext.getRequestContextPath()
-                + externalContext.getRequestServletPath();
-
-        if (externalContext.getRequestPathInfo() != null)
-        {
-            url += externalContext.getRequestPathInfo();
-        }
-  
-        url = JsfUtils.addRequestParameters(externalContext, url, true);
-        //TODO check if it isn't better to fix addRequestParameters itself
-        //only #encodeResourceURL is portable currently
-        url = facesContext.getExternalContext().encodeResourceURL(url);
-
-        // see #729
-        addRequestWindowIdCookie(facesContext, newWindowId);
-
-        try
-        {
-            externalContext.redirect(url);
-        }
-        catch (IOException e)
-        {
-            throw new FacesException("Could not send initial redirect!", e);
-        }
-    }
-
-    public static boolean isInitialRedirect(FacesContext facesContext)
-    {
-        return facesContext.getAttributes().containsKey(INITIAL_REDIRECT_WINDOW_ID);
-    }
-
-    public static String getInitialRedirectWindowId(FacesContext facesContext)
-    {
-        return (String) facesContext.getAttributes().get(INITIAL_REDIRECT_WINDOW_ID);
-    }
-
-    /**
-     * Appends the current windowId to the given url, if enabled via
-     * {@link ClientWindow#isClientWindowRenderModeEnabled(javax.faces.context.FacesContext)}
-     *
-     * @param facesContext the {@link FacesContext}
-     * @param url the url
-     * @param clientWindow the {@link ClientWindow} to use
-     * @return if enabled, the url with windowId, otherwise the umodified url
-     */
-    public static String appendWindowId(FacesContext facesContext, String url, ClientWindow clientWindow)
-    {
-        if (clientWindow != null && clientWindow.isClientWindowRenderModeEnabled(facesContext))
-        {
-            Map<String, String> parameters = clientWindow.getQueryURLParameters(facesContext);
-
-            if (parameters != null && !parameters.isEmpty())
-            {
-                String targetUrl = url;
-
-                for (Entry<String, String> entry : parameters.entrySet())
-                {
-                    targetUrl = JsfUtils.addParameter(facesContext.getExternalContext(),
-                            targetUrl,
-                            true,
-                            entry.getKey(),
-                            entry.getValue());
-                }
-
-                if (targetUrl.contains("dswid=&"))
-                {
-                    //remove empty dswid parameter
-                    targetUrl = targetUrl.replace("dswid=&", "");
-                }
-                return targetUrl;
-            }
-        }
-
-        return url;
-    }
-    
-    public static void addRequestWindowIdCookie(FacesContext context, String windowId)
-    {
-        Map<String, Object> properties = new HashMap();
-        properties.put("path", "/");
-        properties.put("maxAge", 30);
-
-        context.getExternalContext().addResponseCookie(
-                REQUEST_WINDOW_ID_COOKIE_PREFIX + windowId, windowId, properties);
-    }
-    
-    public static Object getRequestWindowIdCookie(FacesContext context, String windowId)
-    {
-        Map<String, Object> cookieMap = context.getExternalContext().getRequestCookieMap();
-        
-        if (cookieMap.containsKey(REQUEST_WINDOW_ID_COOKIE_PREFIX + windowId))
-        {
-            return cookieMap.get(REQUEST_WINDOW_ID_COOKIE_PREFIX + windowId);
-        }
-        
-        return null;
-    }
-    
-    public static void removeRequestWindowIdCookie(FacesContext context, Cookie cookie)
-    {
-        cookie.setMaxAge(0);
-        ((HttpServletResponse) context.getExternalContext().getResponse()).addCookie(cookie);
-    }
-
-    public static int getMaxWindowIdLength()
-    {
-        int result = JsfBaseConfig.ScopeCustomization.WindowRestriction.ID_MAX_LENGTH;
-
-        if (result > JsfBaseConfig.ScopeCustomization.WindowRestriction.ID_MAX_LENGTH_DEFAULT)
-        {
-            if (LOG.isLoggable(Level.WARNING))
-            {
-                LOG.warning("ATTENTION: if you change this value to be significant longer than 10, " +
-                    "you can introduce a security issue in WindowIdHtmlRenderer. " +
-                    "If you increase it because window.name contains a value already, " +
-                    "please revisit that usage or " +
-                    "create shorter unique ids since they just need to be unique within the user-session.");
-            }
-        }
-        return result;
-    }
-}
+/*
+ * 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.deltaspike.jsf.impl.util;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.enterprise.inject.Typed;
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.deltaspike.jsf.api.config.base.JsfBaseConfig;
+import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow;
+
+@Typed()
+public abstract class ClientWindowHelper
+{
+    private static final Logger LOG = Logger.getLogger(ClientWindowHelper.class.getName());
+
+    private static final String INITIAL_REDIRECT_WINDOW_ID = ClientWindowHelper.class.getName()
+            + ".INITIAL_REDIRECT_WINDOW_ID";
+
+    public abstract class RequestParameters
+    {
+        public static final String POST_WINDOW_ID = "dspwid";
+        public static final String JSF_POST_WINDOW_ID = "javax.faces.ClientWindow";
+        public static final String GET_WINDOW_ID = "dswid";
+        public static final String REQUEST_TOKEN = "dsrid";
+    }
+
+    public abstract class Cookies
+    {
+        public static final String REQUEST_WINDOW_ID_PREFIX = "dsrwid-";
+        public static final String WINDOW_ID_PREFIX = "dsWindowId-";
+    }
+
+
+    /**
+     * Handles the initial redirect for the LAZY mode, if no windowId is available in the current request URL.
+     *
+     * @param facesContext the {@link FacesContext}
+     * @param newWindowId the new windowId
+     */
+    public static void handleInitialRedirect(FacesContext facesContext, String newWindowId)
+    {        
+        // store the new windowId as context attribute to prevent infinite loops
+        // #sendRedirect will append the windowId (from ClientWindow#getWindowId again) to the redirectUrl
+        facesContext.getAttributes().put(INITIAL_REDIRECT_WINDOW_ID, newWindowId);
+
+        ExternalContext externalContext = facesContext.getExternalContext();
+
+        String url = externalContext.getRequestContextPath()
+                + externalContext.getRequestServletPath();
+
+        if (externalContext.getRequestPathInfo() != null)
+        {
+            url += externalContext.getRequestPathInfo();
+        }
+
+        url = JsfUtils.addRequestParameters(externalContext, url, true);
+        //TODO check if it isn't better to fix addRequestParameters itself
+        //only #encodeResourceURL is portable currently
+        url = facesContext.getExternalContext().encodeResourceURL(url);
+
+        // see #729
+        addRequestWindowIdCookie(facesContext, newWindowId);
+
+        try
+        {
+            externalContext.redirect(url);
+        }
+        catch (IOException e)
+        {
+            throw new FacesException("Could not send initial redirect!", e);
+        }
+    }
+
+    public static boolean isInitialRedirect(FacesContext facesContext)
+    {
+        return facesContext.getAttributes().containsKey(INITIAL_REDIRECT_WINDOW_ID);
+    }
+
+    public static String getInitialRedirectWindowId(FacesContext facesContext)
+    {
+        return (String) facesContext.getAttributes().get(INITIAL_REDIRECT_WINDOW_ID);
+    }
+
+    /**
+     * Appends the current windowId to the given url, if enabled via
+     * {@link ClientWindow#isClientWindowRenderModeEnabled(javax.faces.context.FacesContext)}
+     *
+     * @param facesContext the {@link FacesContext}
+     * @param url the url
+     * @param clientWindow the {@link ClientWindow} to use
+     * @return if enabled, the url with windowId, otherwise the umodified url
+     */
+    public static String appendWindowId(FacesContext facesContext, String url, ClientWindow clientWindow)
+    {
+        if (clientWindow != null && clientWindow.isClientWindowRenderModeEnabled(facesContext))
+        {
+            Map<String, String> parameters = clientWindow.getQueryURLParameters(facesContext);
+
+            if (parameters != null && !parameters.isEmpty())
+            {
+                String targetUrl = url;
+
+                for (Entry<String, String> entry : parameters.entrySet())
+                {
+                    targetUrl = JsfUtils.addParameter(facesContext.getExternalContext(),
+                            targetUrl,
+                            true,
+                            entry.getKey(),
+                            entry.getValue());
+
+                    //remove empty parameter (e.g. dswid)
+                    String emptyParameter = entry.getKey() + "=&";
+                    if (targetUrl.contains(emptyParameter))
+                    {
+                        targetUrl = targetUrl.replace(emptyParameter, "");
+                    }
+                }
+                return targetUrl;
+            }
+        }
+
+        return url;
+    }
+
+    public static void addRequestWindowIdCookie(FacesContext context, String windowId)
+    {
+        Map<String, Object> properties = new HashMap();
+        properties.put("path", "/");
+        properties.put("maxAge", 30);
+
+        context.getExternalContext().addResponseCookie(
+                Cookies.REQUEST_WINDOW_ID_PREFIX + windowId, windowId, properties);
+    }
+
+    public static Object getRequestWindowIdCookie(FacesContext context, String windowId)
+    {
+        Map<String, Object> cookieMap = context.getExternalContext().getRequestCookieMap();
+
+        if (cookieMap.containsKey(Cookies.REQUEST_WINDOW_ID_PREFIX + windowId))
+        {
+            return cookieMap.get(Cookies.REQUEST_WINDOW_ID_PREFIX + windowId);
+        }
+
+        return null;
+    }
+
+    public static void removeRequestWindowIdCookie(FacesContext context, Cookie cookie)
+    {
+        cookie.setMaxAge(0);
+        ((HttpServletResponse) context.getExternalContext().getResponse()).addCookie(cookie);
+    }
+
+    public static int getMaxWindowIdLength()
+    {
+        int result = JsfBaseConfig.ScopeCustomization.WindowRestriction.ID_MAX_LENGTH;
+
+        if (result > JsfBaseConfig.ScopeCustomization.WindowRestriction.ID_MAX_LENGTH_DEFAULT)
+        {
+            if (LOG.isLoggable(Level.WARNING))
+            {
+                LOG.warning("ATTENTION: if you change this value to be significant longer than 10, " +
+                    "you can introduce a security issue in WindowIdHtmlRenderer. " +
+                    "If you increase it because window.name contains a value already, " +
+                    "please revisit that usage or " +
+                    "create shorter unique ids since they just need to be unique within the user-session.");
+            }
+        }
+        return result;
+    }
+}