You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by st...@apache.org on 2013/04/21 21:46:15 UTC

[1/3] git commit: DELTASPIKE-289 implement ClientWindowConfig

Updated Branches:
  refs/heads/master ac93bc54a -> 45770596d


DELTASPIKE-289 implement ClientWindowConfig

This can be used to determine the window handling behaviour
for each request.


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

Branch: refs/heads/master
Commit: ff5df7d320c9819754586497eb36a07a2d384652
Parents: ac93bc5
Author: Mark Struberg <st...@apache.org>
Authored: Sun Apr 21 10:54:54 2013 +0200
Committer: Mark Struberg <st...@apache.org>
Committed: Sun Apr 21 10:54:54 2013 +0200

----------------------------------------------------------------------
 .../core/impl/scope/window/WindowBeanHolder.java   |   13 +-
 .../core/impl/scope/window/WindowContextImpl.java  |    4 +-
 deltaspike/modules/jsf/api/pom.xml                 |   11 +
 .../jsf/spi/window/ClientWindowConfig.java         |   79 ++++++
 .../jsf/spi/window/DefaultClientWindowConfig.java  |  215 +++++++++++++++
 5 files changed, 315 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/ff5df7d3/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
index 8acd0e6..b4acc46 100644
--- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
@@ -43,12 +43,6 @@ public class WindowBeanHolder implements Serializable
      */
     private volatile Map<String, ContextualStorage> storageMap = new ConcurrentHashMap<String, ContextualStorage>();
 
-    //X TODO review usage
-    public Map<String, ContextualStorage> getStorageMap()
-    {
-        return storageMap;
-    }
-
     /**
      * This method will return the ContextualStorage or create a new one
      * if no one is yet assigned to the current windowId.
@@ -90,6 +84,13 @@ public class WindowBeanHolder implements Serializable
         return oldStorageMap;
     }
 
+    /**
+     * This method properly destroys all current &#064;WindowScoped beans
+     * of the active session and also prepares the storage for new beans.
+     * It will automatically get called when the session context closes
+     * but can also get invoked manually, e.g. if a user likes to get rid
+     * of all it's &#064;WindowScoped beans.
+     */
     @PreDestroy
     public void destroyBeans()
     {

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/ff5df7d3/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
index e9aa326..ebda229 100644
--- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowContextImpl.java
@@ -30,7 +30,9 @@ import org.apache.deltaspike.core.util.context.AbstractContext;
 import org.apache.deltaspike.core.util.context.ContextualStorage;
 
 /**
- * Context to handle &#064;{@link WindowScoped} beans.
+ * CDI Context to handle &#064;{@link WindowScoped} beans.
+ * This also implements the interface to control the id of
+ * the currently active 'window' (e.g. a web browser tab).
  */
 @Typed()
 public class WindowContextImpl extends AbstractContext implements WindowContext

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/ff5df7d3/deltaspike/modules/jsf/api/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/pom.xml b/deltaspike/modules/jsf/api/pom.xml
index cdc9c63..874148c 100644
--- a/deltaspike/modules/jsf/api/pom.xml
+++ b/deltaspike/modules/jsf/api/pom.xml
@@ -36,6 +36,17 @@
             <groupId>org.apache.deltaspike.core</groupId>
             <artifactId>deltaspike-core-api</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_2.5_spec</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.myfaces.core</groupId>
+            <artifactId>myfaces-api</artifactId>
+        </dependency>
+
+
     </dependencies>
 
 

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/ff5df7d3/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/ClientWindowConfig.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/ClientWindowConfig.java b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/ClientWindowConfig.java
new file mode 100644
index 0000000..94690ec
--- /dev/null
+++ b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/ClientWindowConfig.java
@@ -0,0 +1,79 @@
+/*
+ * 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.spi.window;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * Configuration for ClientWindow handler which is used
+ * to determine the correct windowId for &#063;WindowScoped beans.
+ */
+public interface ClientWindowConfig
+{
+    public enum ClientWindowRenderMode
+    {
+        /**
+         * Any window or browser tab detection is disabled for this request
+         */
+        NONE,
+
+        /**
+         * <p>The GET request results in an intermediate small html page which
+         * checks if the browser tab fits the selected windowId</p>
+         * <p>The ClientWindow html extracts the windowId from the window.name and
+         * enforces a 2nd GET which will contain the windowId and will get routed
+         * through to the target JSF page.</p>
+         */
+        CLIENTWINDOW,
+
+        /**
+         * Render each GET request with the windowId you get during the request
+         * and perform a lazy check on the client side via JavaScript or similar.
+         */
+        LAZY
+
+    }
+
+    /**
+     * @return whether JavaScript is enabled
+     */
+    boolean isJavaScriptEnabled();
+
+    /**
+     * @param javaScriptEnabled whether JavaScript is enabled
+     */
+    void setJavaScriptEnabled(boolean javaScriptEnabled);
+
+    /**
+     * Determine whether this request should take care of clientWindow detection.
+     * This can e.g. get disabled for download pages or if a useragent doesn't
+     * support html5 or any other required technique.
+     * This only gets checked for GET requests!
+     *
+     * @param facesContext
+     * @return the selected ClientWindowRenderMode
+     */
+    ClientWindowRenderMode getClientWindowRenderMode(FacesContext facesContext);
+
+    /**
+     * @return the prepared html which gets sent out to the client as intermediate client window.
+     */
+    String getClientWindowHtml();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/ff5df7d3/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/DefaultClientWindowConfig.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/DefaultClientWindowConfig.java b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/DefaultClientWindowConfig.java
new file mode 100644
index 0000000..dbec591
--- /dev/null
+++ b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/DefaultClientWindowConfig.java
@@ -0,0 +1,215 @@
+/*
+ * 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.spi.window;
+
+import javax.enterprise.context.SessionScoped;
+import javax.faces.context.FacesContext;
+import javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.deltaspike.core.api.projectstage.ProjectStage;
+import org.apache.deltaspike.core.util.ClassUtils;
+import org.apache.deltaspike.core.util.ExceptionUtils;
+
+/**
+ * Default implementation of {@link ClientWindowConfig}.
+ * It will use the internal <code>windowhandler.html</code>
+ */
+@SessionScoped
+public class DefaultClientWindowConfig implements ClientWindowConfig, Serializable
+{
+    /**
+     * We will set a cookie with this very name if a noscript link got clicked by the user
+     */
+    public static final String COOKIE_NAME_NOSCRIPT_ENABLED = "deltaspikeNoScriptEnabled";
+
+    /**
+     * The location of the default windowhandler resource
+     */
+    private static final String DEFAULT_WINDOW_HANDLER_HTML_FILE = "static/windowhandler.html";
+
+
+    private volatile Boolean javaScriptEnabled = null;
+
+    /**
+     * lazily initiated via {@link #getUserAgent(javax.faces.context.FacesContext)}
+     */
+    private volatile String userAgent = null;
+
+    /**
+     * Contains the cached ClientWindow handler html for this session.
+     */
+    private String clientWindowtml;
+
+    @Inject
+    private ProjectStage projectStage;
+
+
+    @Override
+    public boolean isJavaScriptEnabled()
+    {
+        if (javaScriptEnabled == null)
+        {
+            synchronized (this)
+            {
+                // double lock checking idiom on volatile variable works since java5
+                if (javaScriptEnabled == null)
+                {
+                    // no info means that it is default -> true
+                    javaScriptEnabled = Boolean.TRUE;
+
+                    FacesContext facesContext = FacesContext.getCurrentInstance();
+                    if (facesContext != null)
+                    {
+                        Cookie cookie = (Cookie) facesContext.getExternalContext().
+                                getRequestCookieMap().get(COOKIE_NAME_NOSCRIPT_ENABLED);
+                        if (cookie != null)
+                        {
+                            javaScriptEnabled = Boolean.parseBoolean(cookie.getValue());
+                        }
+                    }
+                }
+            }
+        }
+        return javaScriptEnabled;
+    }
+
+
+    @Override
+    public void setJavaScriptEnabled(boolean javaScriptEnabled)
+    {
+        this.javaScriptEnabled = Boolean.valueOf(javaScriptEnabled);
+    }
+
+    /**
+     * By default we use {@link ClientWindowRenderMode#CLIENTWINDOW} unless
+     * we detect a bot.
+     * Override this method to exclude other requests from getting accessed.
+     *
+     * @param facesContext
+     * @return
+     */
+    @Override
+    public ClientWindowRenderMode getClientWindowRenderMode(FacesContext facesContext)
+    {
+        if (!isJavaScriptEnabled())
+        {
+            return ClientWindowRenderMode.NONE;
+        }
+
+        String userAgent = getUserAgent(facesContext);
+
+        if (userAgent != null &&
+            ( userAgent.indexOf("bot")     >= 0 || // Googlebot, etc
+              userAgent.indexOf("Bot")     >= 0 || // BingBot, etc
+              userAgent.indexOf("Slurp")   >= 0 || // Yahoo Slurp
+              userAgent.indexOf("Crawler") >= 0    // various other Crawlers
+            ) )
+        {
+            return ClientWindowRenderMode.NONE;
+        }
+
+        return ClientWindowRenderMode.CLIENTWINDOW;
+    }
+
+    @Override
+    public String getClientWindowHtml()
+    {
+        if (projectStage != ProjectStage.Development && clientWindowtml != null)
+        {
+            // use cached windowHandlerHtml except in Development
+            return clientWindowtml;
+        }
+
+        InputStream is = ClassUtils.getClassLoader(null).getResourceAsStream(getClientWindowResourceLocation());
+        StringBuffer sb = new StringBuffer();
+        try
+        {
+            byte[] buf = new byte[16 * 1024];
+            int bytesRead;
+            while ((bytesRead = is.read(buf)) != -1)
+            {
+                String sbuf = new String(buf, 0, bytesRead);
+                sb.append(sbuf);
+            }
+        }
+        catch (IOException e)
+        {
+            ExceptionUtils.throwAsRuntimeException(e);
+        }
+        finally
+        {
+            try
+            {
+                is.close();
+            }
+            catch (IOException e)
+            {
+                // do nothing, all fine so far
+            }
+        }
+
+        clientWindowtml = sb.toString();
+
+        return clientWindowtml;
+    }
+
+    /**
+     * This information will get stored as it cannot
+     * change during the session anyway.
+     * @return the UserAgent of the request.
+     */
+    public String getUserAgent(FacesContext facesContext)
+    {
+        if (userAgent == null)
+        {
+            synchronized (this)
+            {
+                if (userAgent == null)
+                {
+                    Map<String, String[]> requestHeaders =
+                            facesContext.getExternalContext().getRequestHeaderValuesMap();
+
+                    if (requestHeaders != null &&
+                            requestHeaders.containsKey("User-Agent"))
+                    {
+                        String[] userAgents = requestHeaders.get("User-Agent");
+                        userAgent = userAgents.length > 0 ? userAgents[0] : null;
+                    }
+                }
+            }
+        }
+
+        return userAgent;
+    }
+
+
+    /**
+     * Overwrite this to define your own ClientWindow handler html location.
+     * This will get picked up as resource from the classpath.
+     */
+    public String getClientWindowResourceLocation()
+    {
+        return DEFAULT_WINDOW_HANDLER_HTML_FILE;
+    }
+}


[3/3] git commit: DELTASPIKE-289 migrate windowhandler from CODI

Posted by st...@apache.org.
DELTASPIKE-289 migrate windowhandler from CODI


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

Branch: refs/heads/master
Commit: 45770596d64be289e202339bbc02ebb22aed3758
Parents: 30661b0
Author: Mark Struberg <st...@apache.org>
Authored: Sun Apr 21 20:56:15 2013 +0200
Committer: Mark Struberg <st...@apache.org>
Committed: Sun Apr 21 20:56:15 2013 +0200

----------------------------------------------------------------------
 .../core/impl/scope/window/WindowBeanHolder.java   |    7 +-
 deltaspike/modules/jsf/impl/pom.xml                |    4 +
 .../request/DeltaSpikeLifecycleWrapper.java        |   30 ++-
 .../jsf/impl/scope/window/DefaultClientWindow.java |  165 +++++++++++++-
 .../META-INF/resources/js/windowhandler.js         |  180 +++++++++++++++
 .../src/main/resources/static/windowhandler.html   |  170 ++++++++++++++
 6 files changed, 545 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
index b4acc46..429fa20 100644
--- a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/scope/window/WindowBeanHolder.java
@@ -41,7 +41,7 @@ public class WindowBeanHolder implements Serializable
      * value: the {@link ContextualStorage} which holds all the
      * {@link javax.enterprise.inject.spi.Bean}s.
      */
-    private volatile Map<String, ContextualStorage> storageMap = new ConcurrentHashMap<String, ContextualStorage>();
+    private Map<String, ContextualStorage> storageMap = new ConcurrentHashMap<String, ContextualStorage>();
 
     /**
      * This method will return the ContextualStorage or create a new one
@@ -67,6 +67,11 @@ public class WindowBeanHolder implements Serializable
         return contextualStorage;
     }
 
+    public Map<String, ContextualStorage> getStorageMap()
+    {
+        return storageMap;
+    }
+
     /**
      *
      * This method will replace the storageMap and with

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/pom.xml b/deltaspike/modules/jsf/impl/pom.xml
index c71899f..ee9947c 100644
--- a/deltaspike/modules/jsf/impl/pom.xml
+++ b/deltaspike/modules/jsf/impl/pom.xml
@@ -65,6 +65,10 @@
             <version>1.0</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-servlet_3.0_spec</artifactId>
+        </dependency>
 
         <!-- we use Arquillian Warp to test our JSF apps -->
         <dependency>

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
index 9d4808d..0f91b33 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
@@ -19,7 +19,9 @@
 package org.apache.deltaspike.jsf.impl.listener.request;
 
 import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.spi.scope.window.WindowContext;
 import org.apache.deltaspike.core.util.ClassDeactivationUtils;
+import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow;
 
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseListener;
@@ -31,6 +33,9 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
 
     private BeforeAfterJsfRequestBroadcaster beforeAfterJsfRequestBroadcaster;
 
+    private ClientWindow clientWindow;
+    private WindowContext windowContext;
+
     private volatile Boolean initialized;
 
     DeltaSpikeLifecycleWrapper(Lifecycle wrapped)
@@ -53,13 +58,19 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
     @Override
     public void execute(FacesContext facesContext)
     {
+        lazyInit();
+
         //TODO broadcastApplicationStartupBroadcaster();
         broadcastBeforeFacesRequestEvent(facesContext);
 
-        //X TODO add ClientWindow handling
-        this.wrapped.execute(facesContext);
-
+        // ClientWindow handling
+        String windowId = clientWindow.getWindowId(facesContext);
+        if (windowId != null)
+        {
+            windowContext.activateWindow(windowId);
+        }
 
+        this.wrapped.execute(facesContext);
     }
 
     @Override
@@ -85,7 +96,6 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
 
     private void broadcastBeforeFacesRequestEvent(FacesContext facesContext)
     {
-        lazyInit();
         if (this.beforeAfterJsfRequestBroadcaster != null)
         {
             this.beforeAfterJsfRequestBroadcaster.broadcastBeforeJsfRequestEvent(facesContext);
@@ -103,15 +113,21 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
     private synchronized void init()
     {
         // switch into paranoia mode
-        if (this.initialized == null)
+        if (initialized == null)
         {
             if (ClassDeactivationUtils.isActivated(BeforeAfterJsfRequestBroadcaster.class))
             {
-                this.beforeAfterJsfRequestBroadcaster =
+                beforeAfterJsfRequestBroadcaster =
                         BeanProvider.getContextualReference(BeforeAfterJsfRequestBroadcaster.class, true);
+
+                clientWindow =
+                        BeanProvider.getContextualReference(ClientWindow.class, true);
+
+                windowContext =
+                        BeanProvider.getContextualReference(WindowContext.class, true);
             }
 
-            this.initialized = true;
+            initialized = true;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/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 4ab6d37..3ea9478 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
@@ -19,13 +19,20 @@
 package org.apache.deltaspike.jsf.impl.scope.window;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.faces.FacesException;
 import javax.faces.component.UIViewRoot;
+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.logging.Logger;
 
 import org.apache.deltaspike.core.spi.scope.window.WindowContext;
+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;
 
@@ -46,6 +53,24 @@ public class DefaultClientWindow implements ClientWindow
 {
     private static final Logger logger = Logger.getLogger(DefaultClientWindow.class.getName());
 
+    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";
+
 
     @Inject
     private ClientWindowConfig clientWindowConfig;
@@ -59,16 +84,36 @@ public class DefaultClientWindow implements ClientWindow
     {
         if (ClientWindowRenderMode.NONE.equals(clientWindowConfig.getClientWindowRenderMode(facesContext)))
         {
-            return null;
+            // if this request should not get any window detection then we are done
+            return DEFAULT_WINDOW_ID;
         }
 
-        String windowId = null;
-
         if (facesContext.isPostback())
         {
+            // for POST we read the windowId from the WindowIdHolderComponent in our ViewRoot
             return getPostBackWindowId(facesContext);
         }
 
+        ExternalContext externalContext = facesContext.getExternalContext();
+
+        // and now for the GET request stuff
+        if (isNoscriptRequest(externalContext))
+        {
+            // the client has JavaScript disabled
+            clientWindowConfig.setJavaScriptEnabled(false);
+
+            return DEFAULT_WINDOW_ID;
+        }
+
+        String windowId = getVerifiedWindowIdFromCookie(externalContext);
+        if (windowId == null)
+        {
+            // GET request without windowId - send windowhandlerfilter.html to get the windowId
+            sendWindowHandlerHtml(externalContext, null);
+            facesContext.responseComplete();
+        }
+
+        // we have a valid windowId - set it and continue with the request
         return windowId;
     }
 
@@ -93,4 +138,118 @@ public class DefaultClientWindow implements ClientWindow
     }
 
 
+    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);
+
+        // add noscript parameter
+        if (url.contains("?"))
+        {
+            url = url + "&";
+        }
+        else
+        {
+            url = url + "?";
+        }
+        url = url + 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 "";
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/js/windowhandler.js
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/js/windowhandler.js b/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/js/windowhandler.js
new file mode 100644
index 0000000..b563b31
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/resources/META-INF/resources/js/windowhandler.js
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+(function() {
+//wrapping so that all internal functions are privately scoped
+function isHtml5() {
+    try {
+        return !!localStorage.getItem;
+    } catch(e) {
+        return false;
+    }
+}
+
+// some browsers don't understand JSON - guess which one ... :(
+function stringify(someArray) {
+    if (JSON) {
+        return JSON.stringify(someArray);
+    }
+    return someArray.join("|||");
+}
+
+// store the current body in the html5 localstorage
+function storeWindowTree() {
+    // first we store all CSS we also need on the intermediate page
+    var headNodes = document.getElementsByTagName("head")[0].childNodes;
+    var oldSS = new Array();
+    var j = 0;
+    for (var i = 0; i < headNodes.length; i++) {
+        var tagName = headNodes[i].tagName;
+        if (tagName && equalsIgnoreCase(tagName, "link") &&
+                equalsIgnoreCase(headNodes[i].getAttribute("type"), "text/css")) {
+
+            // sort out media="print" and stuff
+            var media = headNodes[i].getAttribute("media");
+            if (!media || equalsIgnoreCase(media, "all") || equalsIgnoreCase(media, 'screen')) {
+                oldSS[j++] = headNodes[i].getAttribute("href");
+            }
+        }
+    }
+    localStorage.setItem(window.name + '_css', stringify(oldSS));
+    var body = document.getElementsByTagName("body")[0];
+    localStorage.setItem(window.name + '_body', body.innerHTML);
+    //X TODO: store ALL attributes of the body tag
+    localStorage.setItem(window.name + '_bodyAttrs', body.getAttribute("class"));
+    return true;
+}
+
+function equalsIgnoreCase(source, destination) {
+    //either both are not set or null
+    if (!source && !destination) {
+        return true;
+    }
+    //source or dest is set while the other is not
+    if (!source || !destination) return false;
+
+    //in any other case we do a strong string comparison
+    return source.toLowerCase() === destination.toLowerCase();
+}
+
+/** This method will be called onWindowLoad and after AJAX success */
+function applyOnClick() {
+    var links = document.getElementsByTagName("a");
+    for (var i = 0; i < links.length; i++) {
+        if (!links[i].onclick) {
+            links[i].onclick = function() {storeWindowTree(); return true;};
+        } else {
+            // prevent double decoration
+            if (!("" + links[i].onclick).match(".*storeWindowTree().*")) {
+                //the function wrapper is important otherwise the
+                //last onclick handler would be assigned to oldonclick
+                (function storeEvent() {
+                    var oldonclick = links[i].onclick;
+                    links[i].onclick = function(evt) {
+                        //ie handling added
+                        evt = evt || window.event;
+
+                        return storeWindowTree() && oldonclick(evt);
+                    };
+                })();
+            }
+        }
+    }
+}
+
+function getUrlParameter(name) {
+    var url = window.location.href;
+    var vars = url.split(/&|\?/g);
+    for (var i=0; vars != null && i < vars.length; i++) {
+        var pair = vars[i].split("=");
+        if (pair[0]==name) {
+            return pair[1];
+        }
+    }
+    return null;
+}
+function setUrlParam(baseUrl, paramName, paramValue) {
+    var query = baseUrl;
+    var vars = query.split(/&|\?/g);
+    var newQuery = "";
+    var iParam = 0;
+    var paramFound = false;
+    for (var i=0; vars != null && i < vars.length; i++) {
+        var pair = vars[i].split("=");
+        if (pair.length == 1) {
+            newQuery = pair[0];
+        } else {
+            if (pair[0] != paramName) {
+                var amp = iParam++ > 0 ? "&" : "?";
+                newQuery =  newQuery + amp + pair[0] + "=" + pair[1];
+            } else {
+                paramFound = true;
+                if (paramValue) {
+                    var amp = iParam++ > 0 ? "&" : "?";
+                    newQuery =  newQuery + amp + paramName + "=" + paramValue;
+                }
+            }
+        }
+    }
+    if (!paramFound && paramValue) {
+        var amp = iParam++ > 0 ? "&" : "?";
+        newQuery =  newQuery + amp + paramName + "=" + paramValue;
+    }
+    return newQuery;
+}
+// this method runs to ensure that windowIds get checked even if no windowhandler.html is used
+function assertWindowId() {
+    if (!window.name || window.name.length < 1) {
+        url = setUrlParam(window.location.href, 'windowId', null);
+        window.name = 'tempWindowId';
+        window.location = url;
+    }
+}
+
+function eraseRequestCookie() {
+    var requestToken = getUrlParameter('dsRid'); // random request param
+    if (requestToken) {
+        var cookieName = 'dsiWindowId-' + requestToken;
+        var date = new Date();
+        date.setTime(date.getTime()-(10*24*60*60*1000)); // - 10 day
+        var expires = "; expires="+date.toGMTString();
+        document.cookie = cookieName+"="+expires+"; path=/";
+    }
+}
+
+var ajaxOnClick = function ajaxDecorateClick(event) {
+    if (event.status=="success") {
+        applyOnClick();
+    }
+}
+
+var oldWindowOnLoad = window.onload;
+
+window.onload = function(evt) {
+    try {
+        (oldWindowOnLoad)? oldWindowOnLoad(evt): null;
+    } finally {
+        eraseRequestCookie(); // manually erase the old dsRid cookie because Firefox doesn't do it properly
+        assertWindowId();
+        if (isHtml5()) {
+            applyOnClick();
+            jsf.ajax.addOnEvent(ajaxOnClick);
+        }
+    }
+}
+})();

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/45770596/deltaspike/modules/jsf/impl/src/main/resources/static/windowhandler.html
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/resources/static/windowhandler.html b/deltaspike/modules/jsf/impl/src/main/resources/static/windowhandler.html
new file mode 100644
index 0000000..c096722
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/resources/static/windowhandler.html
@@ -0,0 +1,170 @@
+<!DOCTYPE html
+  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!--
+ 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.
+-->
+<html>
+
+<head><title>Loading...</title></head>
+<body $$bodyAttributes$$><div id="message" style="position:absolute;left:40%;top:40%">
+    Your browser does not support JavaScript.
+    Click <a href="$$noscriptUrl$$">here</a> to continue without JavaScript.
+</div></body>
+
+<script type="text/javascript" >
+function isHtml5() {
+    try { return !!localStorage.getItem;
+    } catch(e) { return false; }
+}
+function unstringify(serialized) {
+    if (JSON) { return JSON.parse(serialized); }
+    return serialized.split("|||");
+}
+function getOldBody() {
+    if (window.name.length != null) {
+        return localStorage.getItem(window.name + '_body');
+    }
+}
+function getOldBodyAttrs() {
+    if (window.name.length != null) {
+        return localStorage.getItem(window.name + '_bodyAttrs');
+    }
+}
+function getOldCss() {
+    if (window.name.length != null) {
+        return unstringify(localStorage.getItem(window.name + '_css'));
+    }
+}
+
+function addCss(url) {
+    var newSS = document.createElement("style");
+    newSS.setAttribute("rel", "stylesheet");
+    newSS.setAttribute("type", "text/css");
+    newSS.appendChild(document.createTextNode("@import url(" +url + ");"));
+    document.getElementsByTagName("head")[0].appendChild(newSS);
+}
+
+function loadCss(clean) {
+    if (!isHtml5()) { // only do this stuff on html browsers
+        return;
+    }
+    var oldCss  = getOldCss();
+    if (window.name && oldCss) {
+        for (i=0; oldCss && i< oldCss.length; i++) {
+            addCss(oldCss[i]);
+        }
+        if (clean) {
+            localStorage.removeItem(window.name + '_css');
+        }
+    }
+}
+
+function replaceContent() {
+    if (!isHtml5()) { // only do this stuff on html browsers
+        document.getElementById('message').textContent = "Loading...";
+        return;
+    }
+    loadCss(false);
+
+    var oldBody = getOldBody();
+
+    if (window.name && oldBody) {
+        document.body.innerHTML = oldBody;
+
+        //X TODO should restore all attribs of the body tag
+        document.body.setAttribute("class", getOldBodyAttrs());
+        document.body.setAttribute("style", " cursor: wait !important;");
+
+        localStorage.removeItem(window.name + '_body');
+        localStorage.removeItem(window.name + '_bodyAttrs');
+
+        // overlay the doc with an un-clickable full-size div
+        var newDiv = document.createElement("div");
+        newDiv.setAttribute("style", "position:absolute; z-index:1000; background-color:transparent; top:0; left:0; width:100%; height: 100%");
+        newDiv.setAttribute("class", "fulldiv");
+        document.body.appendChild(newDiv);
+    } else {
+        document.getElementById('message').textContent = "Loading...";
+    }
+}
+
+function setUrlParam(baseUrl, paramName, paramValue) {
+    var query = baseUrl;
+    var vars = query.split(/&|\?/g);
+    var newQuery = "";
+    var iParam = 0;
+    var paramFound = false;
+    for (var i=0; vars != null && i < vars.length; i++) {
+        var pair = vars[i].split("=");
+        if (pair.length == 1) {
+            newQuery = pair[0];
+        } else {
+            if (pair[0] != paramName) {
+                var amp = iParam++ > 0 ? "&" : "?";
+                newQuery =  newQuery + amp + pair[0] + "=" + pair[1];
+            } else {
+                paramFound = true;
+                var amp = iParam++ > 0 ? "&" : "?";
+                newQuery =  newQuery + amp + paramName + "=" + paramValue;
+            }
+        }
+    }
+    if (!paramFound) {
+        var amp = iParam++ > 0 ? "&" : "?";
+        newQuery =  newQuery + amp + paramName + "=" + paramValue;
+    }
+    return newQuery;
+}
+
+replaceContent();
+
+window.onload = function() {
+    loadCss(true);
+    // this will be replaced in the phase listener
+    var windowId = '$$windowIdValue$$';
+    if (windowId == 'uninitializedWindowId') {
+        windowId = window.name
+    }
+    if (!windowId || windowId.length < 1) {
+        // request a new windowId
+        windowId = 'automatedEntryPoint';
+    }
+
+    window.name = windowId;
+
+    // uncomment the following line to debug the intermediate page
+    // if (!confirm('reload?')) { return true; }
+
+    // 3 seconds expiry time
+    var expdt = new Date();
+    expdt.setTime(expdt.getTime()+(3*1000));
+    var expires = "; expires="+expdt.toGMTString();
+
+    var requestToken = Math.floor(Math.random()*1001);
+    var newUrl = setUrlParam(window.location.href, "dsRid", requestToken);
+    newUrl = setUrlParam(newUrl, "windowId", windowId);
+
+    document.cookie = 'dsWindowId-' + requestToken + '=' + windowId + expires+"; path=/";
+
+    window.location = newUrl;
+}
+</script>
+
+</html>
+


[2/3] git commit: DELTASPIKE-289 add postback handling for windowId

Posted by st...@apache.org.
DELTASPIKE-289 add postback handling for windowId


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

Branch: refs/heads/master
Commit: 30661b0551940cf7e40b3db2dd3263b3d8b23c2a
Parents: ff5df7d
Author: Mark Struberg <st...@apache.org>
Authored: Sun Apr 21 19:48:47 2013 +0200
Committer: Mark Struberg <st...@apache.org>
Committed: Sun Apr 21 19:48:47 2013 +0200

----------------------------------------------------------------------
 .../META-INF/apache-deltaspike.properties          |   26 +-
 .../jsf/spi/scope/window/ClientWindow.java         |   51 ++++
 .../jsf/spi/scope/window/ClientWindowConfig.java   |   84 ++++++
 .../scope/window/DefaultClientWindowConfig.java    |  218 +++++++++++++++
 .../jsf/spi/window/ClientWindowConfig.java         |   79 ------
 .../jsf/spi/window/DefaultClientWindowConfig.java  |  215 --------------
 .../request/DeltaSpikeLifecycleWrapper.java        |    3 +
 .../jsf/impl/scope/window/DefaultClientWindow.java |   96 +++++++
 .../impl/scope/window/WindowIdHolderComponent.java |  154 ++++++++++
 .../scope/window/WindowIdRenderKitFactory.java     |  101 +++++++
 .../scope/window/WindowIdRenderKitWrapper.java     |   92 ++++++
 .../src/main/resources/META-INF/faces-config.xml   |    3 +-
 12 files changed, 814 insertions(+), 308 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties b/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties
index c20b420..b935ffc 100644
--- a/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties
+++ b/deltaspike/core/impl/src/test/resources/META-INF/apache-deltaspike.properties
@@ -1,19 +1,19 @@
-#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
+# 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.
+# 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.
 
 testProperty03=test_value_03
 org.apache.deltaspike.core.spi.activation.ClassDeactivator=org.apache.deltaspike.test.core.impl.activation.TestClassDeactivator

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/ClientWindow.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/ClientWindow.java b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/ClientWindow.java
new file mode 100644
index 0000000..d272f33
--- /dev/null
+++ b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/ClientWindow.java
@@ -0,0 +1,51 @@
+/*
+ * 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.spi.scope.window;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>API to interact with the window/browser tab handling.
+ * This originally got implemented in Apache MyFaces CODI
+ * which was the basis for the respective feature in JSF-2.2.
+ * We now orientate us a bit on the JSF-2.2 API for making it
+ * easier to provide this feature for JSF-2.0, JSF-2.1 and also
+ * JSF-2.2 JSF implementations.</p>
+ *
+ * <p>Please not that in JSF-2.2 a <code>javax.faces.lifecycle.ClientWindow</code>
+ * instance gets created for each and every request, but in DeltaSpike our
+ * ClientWindow instances are most likely &#064;ApplicationScoped.
+ * </p>
+ */
+public interface ClientWindow
+{
+
+    /**
+     * Extract the windowId for the current request.
+     * This method is intended to get executed at the start of the JSF lifecycle.
+     * We also need to take care about JSF-2.2 ClientWindow in the future.
+     * Depending on the {@link ClientWindowConfig.ClientWindowRenderMode} and
+     * after consulting {@link ClientWindowConfig} we will first send an
+     * intermediate page if the request is an initial GET request.
+     *
+     * @param facesContext for the request
+     * @return the extracted WindowId of the Request, or <code>null</code> if there is no window assigned.
+     */
+    String getWindowId(FacesContext facesContext);
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/ClientWindowConfig.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/ClientWindowConfig.java b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/ClientWindowConfig.java
new file mode 100644
index 0000000..dd3c5db
--- /dev/null
+++ b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/ClientWindowConfig.java
@@ -0,0 +1,84 @@
+/*
+ * 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.spi.scope.window;
+
+import javax.faces.context.FacesContext;
+
+/**
+ * Configuration for ClientWindow handler which is used
+ * to determine the correct windowId for &#063;WindowScoped beans.
+ */
+public interface ClientWindowConfig
+{
+    public enum ClientWindowRenderMode
+    {
+        /**
+         * Any window or browser tab detection is disabled for this request
+         */
+        NONE,
+
+        /**
+         * <p>The GET request results in an intermediate small html page which
+         * checks if the browser tab fits the selected windowId</p>
+         * <p>The ClientWindow html extracts the windowId from the window.name and
+         * enforces a 2nd GET which will contain the windowId and will get routed
+         * through to the target JSF page.</p>
+         */
+        CLIENTWINDOW,
+
+        /**
+         * Render each GET request with the windowId you get during the request
+         * and perform a lazy check on the client side via JavaScript or similar.
+         */
+        LAZY,
+
+        /**
+         * If you set this mode, you also need to provide an own {@link ClientWindow} implementation.
+         */
+        CUSTOM
+
+    }
+
+    /**
+     * @return whether JavaScript is enabled
+     */
+    boolean isJavaScriptEnabled();
+
+    /**
+     * @param javaScriptEnabled whether JavaScript is enabled
+     */
+    void setJavaScriptEnabled(boolean javaScriptEnabled);
+
+    /**
+     * Determine whether this request should take care of clientWindow detection.
+     * This can e.g. get disabled for download pages or if a useragent doesn't
+     * support html5 or any other required technique.
+     * This only gets checked for GET requests!
+     *
+     * @param facesContext
+     * @return the selected ClientWindowRenderMode
+     */
+    ClientWindowRenderMode getClientWindowRenderMode(FacesContext facesContext);
+
+    /**
+     * @return the prepared html which gets sent out to the client as intermediate client window.
+     */
+    String getClientWindowHtml();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/DefaultClientWindowConfig.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/DefaultClientWindowConfig.java b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/DefaultClientWindowConfig.java
new file mode 100644
index 0000000..a3bcf22
--- /dev/null
+++ b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/scope/window/DefaultClientWindowConfig.java
@@ -0,0 +1,218 @@
+/*
+ * 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.spi.scope.window;
+
+import javax.enterprise.context.SessionScoped;
+import javax.faces.context.FacesContext;
+import javax.inject.Inject;
+import javax.servlet.http.Cookie;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.deltaspike.core.api.projectstage.ProjectStage;
+import org.apache.deltaspike.core.util.ClassUtils;
+import org.apache.deltaspike.core.util.ExceptionUtils;
+
+/**
+ * <p>Default implementation of {@link ClientWindowConfig}.
+ * By default it will use the internal <code>windowhandler.html</code></p>
+ *
+ * <p>You can &#064;Specializes this class to tweak the configuration or
+ * provide a completely new implementation as &#064;Alternative.</p>
+ */
+@SessionScoped
+public class DefaultClientWindowConfig implements ClientWindowConfig, Serializable
+{
+    /**
+     * We will set a cookie with this very name if a noscript link got clicked by the user
+     */
+    public static final String COOKIE_NAME_NOSCRIPT_ENABLED = "deltaspikeNoScriptEnabled";
+
+    /**
+     * The location of the default windowhandler resource
+     */
+    private static final String DEFAULT_WINDOW_HANDLER_HTML_FILE = "static/windowhandler.html";
+
+
+    private volatile Boolean javaScriptEnabled = null;
+
+    /**
+     * lazily initiated via {@link #getUserAgent(javax.faces.context.FacesContext)}
+     */
+    private volatile String userAgent = null;
+
+    /**
+     * Contains the cached ClientWindow handler html for this session.
+     */
+    private String clientWindowtml;
+
+    @Inject
+    private ProjectStage projectStage;
+
+
+    @Override
+    public boolean isJavaScriptEnabled()
+    {
+        if (javaScriptEnabled == null)
+        {
+            synchronized (this)
+            {
+                // double lock checking idiom on volatile variable works since java5
+                if (javaScriptEnabled == null)
+                {
+                    // no info means that it is default -> true
+                    javaScriptEnabled = Boolean.TRUE;
+
+                    FacesContext facesContext = FacesContext.getCurrentInstance();
+                    if (facesContext != null)
+                    {
+                        Cookie cookie = (Cookie) facesContext.getExternalContext().
+                                getRequestCookieMap().get(COOKIE_NAME_NOSCRIPT_ENABLED);
+                        if (cookie != null)
+                        {
+                            javaScriptEnabled = Boolean.parseBoolean(cookie.getValue());
+                        }
+                    }
+                }
+            }
+        }
+        return javaScriptEnabled;
+    }
+
+
+    @Override
+    public void setJavaScriptEnabled(boolean javaScriptEnabled)
+    {
+        this.javaScriptEnabled = Boolean.valueOf(javaScriptEnabled);
+    }
+
+    /**
+     * By default we use {@link ClientWindowRenderMode#CLIENTWINDOW} unless
+     * we detect a bot.
+     * Override this method to exclude other requests from getting accessed.
+     *
+     * @param facesContext
+     * @return
+     */
+    @Override
+    public ClientWindowRenderMode getClientWindowRenderMode(FacesContext facesContext)
+    {
+        if (!isJavaScriptEnabled())
+        {
+            return ClientWindowRenderMode.NONE;
+        }
+
+        String userAgent = getUserAgent(facesContext);
+
+        if (userAgent != null &&
+            ( userAgent.indexOf("bot")     >= 0 || // Googlebot, etc
+              userAgent.indexOf("Bot")     >= 0 || // BingBot, etc
+              userAgent.indexOf("Slurp")   >= 0 || // Yahoo Slurp
+              userAgent.indexOf("Crawler") >= 0    // various other Crawlers
+            ) )
+        {
+            return ClientWindowRenderMode.NONE;
+        }
+
+        return ClientWindowRenderMode.CLIENTWINDOW;
+    }
+
+    @Override
+    public String getClientWindowHtml()
+    {
+        if (projectStage != ProjectStage.Development && clientWindowtml != null)
+        {
+            // use cached windowHandlerHtml except in Development
+            return clientWindowtml;
+        }
+
+        InputStream is = ClassUtils.getClassLoader(null).getResourceAsStream(getClientWindowResourceLocation());
+        StringBuffer sb = new StringBuffer();
+        try
+        {
+            byte[] buf = new byte[16 * 1024];
+            int bytesRead;
+            while ((bytesRead = is.read(buf)) != -1)
+            {
+                String sbuf = new String(buf, 0, bytesRead);
+                sb.append(sbuf);
+            }
+        }
+        catch (IOException e)
+        {
+            ExceptionUtils.throwAsRuntimeException(e);
+        }
+        finally
+        {
+            try
+            {
+                is.close();
+            }
+            catch (IOException e)
+            {
+                // do nothing, all fine so far
+            }
+        }
+
+        clientWindowtml = sb.toString();
+
+        return clientWindowtml;
+    }
+
+    /**
+     * This information will get stored as it cannot
+     * change during the session anyway.
+     * @return the UserAgent of the request.
+     */
+    public String getUserAgent(FacesContext facesContext)
+    {
+        if (userAgent == null)
+        {
+            synchronized (this)
+            {
+                if (userAgent == null)
+                {
+                    Map<String, String[]> requestHeaders =
+                            facesContext.getExternalContext().getRequestHeaderValuesMap();
+
+                    if (requestHeaders != null &&
+                            requestHeaders.containsKey("User-Agent"))
+                    {
+                        String[] userAgents = requestHeaders.get("User-Agent");
+                        userAgent = userAgents.length > 0 ? userAgents[0] : null;
+                    }
+                }
+            }
+        }
+
+        return userAgent;
+    }
+
+
+    /**
+     * Overwrite this to define your own ClientWindow handler html location.
+     * This will get picked up as resource from the classpath.
+     */
+    public String getClientWindowResourceLocation()
+    {
+        return DEFAULT_WINDOW_HANDLER_HTML_FILE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/ClientWindowConfig.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/ClientWindowConfig.java b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/ClientWindowConfig.java
deleted file mode 100644
index 94690ec..0000000
--- a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/ClientWindowConfig.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.spi.window;
-
-import javax.faces.context.FacesContext;
-
-/**
- * Configuration for ClientWindow handler which is used
- * to determine the correct windowId for &#063;WindowScoped beans.
- */
-public interface ClientWindowConfig
-{
-    public enum ClientWindowRenderMode
-    {
-        /**
-         * Any window or browser tab detection is disabled for this request
-         */
-        NONE,
-
-        /**
-         * <p>The GET request results in an intermediate small html page which
-         * checks if the browser tab fits the selected windowId</p>
-         * <p>The ClientWindow html extracts the windowId from the window.name and
-         * enforces a 2nd GET which will contain the windowId and will get routed
-         * through to the target JSF page.</p>
-         */
-        CLIENTWINDOW,
-
-        /**
-         * Render each GET request with the windowId you get during the request
-         * and perform a lazy check on the client side via JavaScript or similar.
-         */
-        LAZY
-
-    }
-
-    /**
-     * @return whether JavaScript is enabled
-     */
-    boolean isJavaScriptEnabled();
-
-    /**
-     * @param javaScriptEnabled whether JavaScript is enabled
-     */
-    void setJavaScriptEnabled(boolean javaScriptEnabled);
-
-    /**
-     * Determine whether this request should take care of clientWindow detection.
-     * This can e.g. get disabled for download pages or if a useragent doesn't
-     * support html5 or any other required technique.
-     * This only gets checked for GET requests!
-     *
-     * @param facesContext
-     * @return the selected ClientWindowRenderMode
-     */
-    ClientWindowRenderMode getClientWindowRenderMode(FacesContext facesContext);
-
-    /**
-     * @return the prepared html which gets sent out to the client as intermediate client window.
-     */
-    String getClientWindowHtml();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/DefaultClientWindowConfig.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/DefaultClientWindowConfig.java b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/DefaultClientWindowConfig.java
deleted file mode 100644
index dbec591..0000000
--- a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/spi/window/DefaultClientWindowConfig.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.spi.window;
-
-import javax.enterprise.context.SessionScoped;
-import javax.faces.context.FacesContext;
-import javax.inject.Inject;
-import javax.servlet.http.Cookie;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-import java.util.Map;
-
-import org.apache.deltaspike.core.api.projectstage.ProjectStage;
-import org.apache.deltaspike.core.util.ClassUtils;
-import org.apache.deltaspike.core.util.ExceptionUtils;
-
-/**
- * Default implementation of {@link ClientWindowConfig}.
- * It will use the internal <code>windowhandler.html</code>
- */
-@SessionScoped
-public class DefaultClientWindowConfig implements ClientWindowConfig, Serializable
-{
-    /**
-     * We will set a cookie with this very name if a noscript link got clicked by the user
-     */
-    public static final String COOKIE_NAME_NOSCRIPT_ENABLED = "deltaspikeNoScriptEnabled";
-
-    /**
-     * The location of the default windowhandler resource
-     */
-    private static final String DEFAULT_WINDOW_HANDLER_HTML_FILE = "static/windowhandler.html";
-
-
-    private volatile Boolean javaScriptEnabled = null;
-
-    /**
-     * lazily initiated via {@link #getUserAgent(javax.faces.context.FacesContext)}
-     */
-    private volatile String userAgent = null;
-
-    /**
-     * Contains the cached ClientWindow handler html for this session.
-     */
-    private String clientWindowtml;
-
-    @Inject
-    private ProjectStage projectStage;
-
-
-    @Override
-    public boolean isJavaScriptEnabled()
-    {
-        if (javaScriptEnabled == null)
-        {
-            synchronized (this)
-            {
-                // double lock checking idiom on volatile variable works since java5
-                if (javaScriptEnabled == null)
-                {
-                    // no info means that it is default -> true
-                    javaScriptEnabled = Boolean.TRUE;
-
-                    FacesContext facesContext = FacesContext.getCurrentInstance();
-                    if (facesContext != null)
-                    {
-                        Cookie cookie = (Cookie) facesContext.getExternalContext().
-                                getRequestCookieMap().get(COOKIE_NAME_NOSCRIPT_ENABLED);
-                        if (cookie != null)
-                        {
-                            javaScriptEnabled = Boolean.parseBoolean(cookie.getValue());
-                        }
-                    }
-                }
-            }
-        }
-        return javaScriptEnabled;
-    }
-
-
-    @Override
-    public void setJavaScriptEnabled(boolean javaScriptEnabled)
-    {
-        this.javaScriptEnabled = Boolean.valueOf(javaScriptEnabled);
-    }
-
-    /**
-     * By default we use {@link ClientWindowRenderMode#CLIENTWINDOW} unless
-     * we detect a bot.
-     * Override this method to exclude other requests from getting accessed.
-     *
-     * @param facesContext
-     * @return
-     */
-    @Override
-    public ClientWindowRenderMode getClientWindowRenderMode(FacesContext facesContext)
-    {
-        if (!isJavaScriptEnabled())
-        {
-            return ClientWindowRenderMode.NONE;
-        }
-
-        String userAgent = getUserAgent(facesContext);
-
-        if (userAgent != null &&
-            ( userAgent.indexOf("bot")     >= 0 || // Googlebot, etc
-              userAgent.indexOf("Bot")     >= 0 || // BingBot, etc
-              userAgent.indexOf("Slurp")   >= 0 || // Yahoo Slurp
-              userAgent.indexOf("Crawler") >= 0    // various other Crawlers
-            ) )
-        {
-            return ClientWindowRenderMode.NONE;
-        }
-
-        return ClientWindowRenderMode.CLIENTWINDOW;
-    }
-
-    @Override
-    public String getClientWindowHtml()
-    {
-        if (projectStage != ProjectStage.Development && clientWindowtml != null)
-        {
-            // use cached windowHandlerHtml except in Development
-            return clientWindowtml;
-        }
-
-        InputStream is = ClassUtils.getClassLoader(null).getResourceAsStream(getClientWindowResourceLocation());
-        StringBuffer sb = new StringBuffer();
-        try
-        {
-            byte[] buf = new byte[16 * 1024];
-            int bytesRead;
-            while ((bytesRead = is.read(buf)) != -1)
-            {
-                String sbuf = new String(buf, 0, bytesRead);
-                sb.append(sbuf);
-            }
-        }
-        catch (IOException e)
-        {
-            ExceptionUtils.throwAsRuntimeException(e);
-        }
-        finally
-        {
-            try
-            {
-                is.close();
-            }
-            catch (IOException e)
-            {
-                // do nothing, all fine so far
-            }
-        }
-
-        clientWindowtml = sb.toString();
-
-        return clientWindowtml;
-    }
-
-    /**
-     * This information will get stored as it cannot
-     * change during the session anyway.
-     * @return the UserAgent of the request.
-     */
-    public String getUserAgent(FacesContext facesContext)
-    {
-        if (userAgent == null)
-        {
-            synchronized (this)
-            {
-                if (userAgent == null)
-                {
-                    Map<String, String[]> requestHeaders =
-                            facesContext.getExternalContext().getRequestHeaderValuesMap();
-
-                    if (requestHeaders != null &&
-                            requestHeaders.containsKey("User-Agent"))
-                    {
-                        String[] userAgents = requestHeaders.get("User-Agent");
-                        userAgent = userAgents.length > 0 ? userAgents[0] : null;
-                    }
-                }
-            }
-        }
-
-        return userAgent;
-    }
-
-
-    /**
-     * Overwrite this to define your own ClientWindow handler html location.
-     * This will get picked up as resource from the classpath.
-     */
-    public String getClientWindowResourceLocation()
-    {
-        return DEFAULT_WINDOW_HANDLER_HTML_FILE;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
index 28ad66d..9d4808d 100644
--- a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/listener/request/DeltaSpikeLifecycleWrapper.java
@@ -56,7 +56,10 @@ class DeltaSpikeLifecycleWrapper extends Lifecycle
         //TODO broadcastApplicationStartupBroadcaster();
         broadcastBeforeFacesRequestEvent(facesContext);
 
+        //X TODO add ClientWindow handling
         this.wrapped.execute(facesContext);
+
+
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/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
new file mode 100644
index 0000000..4ab6d37
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/DefaultClientWindow.java
@@ -0,0 +1,96 @@
+/*
+ * 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;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.inject.Inject;
+
+import java.util.logging.Logger;
+
+import org.apache.deltaspike.core.spi.scope.window.WindowContext;
+import org.apache.deltaspike.jsf.spi.scope.window.ClientWindow;
+import org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig;
+
+import static org.apache.deltaspike.jsf.spi.scope.window.ClientWindowConfig.ClientWindowRenderMode;
+
+/**
+ * This is the default implementation of the window/browser tab
+ * detection handling for JSF applications.
+ * This is to big degrees a port of Apache MyFaces CODI
+ * ClientSideWindowHandler.
+ *
+ * It will act according to the configured {@link ClientWindowRenderMode}.
+ *
+ *
+ */
+@ApplicationScoped
+public class DefaultClientWindow implements ClientWindow
+{
+    private static final Logger logger = Logger.getLogger(DefaultClientWindow.class.getName());
+
+
+    @Inject
+    private ClientWindowConfig clientWindowConfig;
+
+    @Inject
+    private WindowContext windowContext;
+
+
+    @Override
+    public String getWindowId(FacesContext facesContext)
+    {
+        if (ClientWindowRenderMode.NONE.equals(clientWindowConfig.getClientWindowRenderMode(facesContext)))
+        {
+            return null;
+        }
+
+        String windowId = null;
+
+        if (facesContext.isPostback())
+        {
+            return getPostBackWindowId(facesContext);
+        }
+
+        return windowId;
+    }
+
+    /**
+     * Extract the windowId for http POST
+     */
+    private String getPostBackWindowId(FacesContext facesContext)
+    {
+        UIViewRoot uiViewRoot = facesContext.getViewRoot();
+
+        if (uiViewRoot != null)
+        {
+            WindowIdHolderComponent existingWindowIdHolder
+                = WindowIdHolderComponent.getWindowIdHolderComponent(uiViewRoot);
+            if (existingWindowIdHolder != null)
+            {
+                return existingWindowIdHolder.getWindowId();
+            }
+        }
+
+        return null;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdHolderComponent.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdHolderComponent.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdHolderComponent.java
new file mode 100644
index 0000000..e4f7326
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdHolderComponent.java
@@ -0,0 +1,154 @@
+/*
+ * 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;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIOutput;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * UI Component holder for the windowId in case of post-backs.
+ * We store this component as direct child in the ViewRoot
+ * and evaluate it's value on postbacks.
+ */
+public class WindowIdHolderComponent extends UIOutput
+{
+    private static final Logger logger = Logger.getLogger(WindowIdHolderComponent.class.getName());
+
+    private String windowId;
+
+    /**
+     * Default constructor might be invoked by the jsf implementation
+     */
+    @SuppressWarnings("UnusedDeclaration")
+    public WindowIdHolderComponent()
+    {
+    }
+
+    /**
+     * Constructor which creates the holder for the given window-id
+     * @param windowId current window-id
+     */
+    public WindowIdHolderComponent(String windowId)
+    {
+        this.windowId = windowId;
+    }
+
+    /**
+     * Needed for server-side window-handler and client-side window handler for supporting postbacks
+     */
+    public static void addWindowIdHolderComponent(FacesContext facesContext, String windowId)
+    {
+        if (windowId == null || windowId.length() == 0)
+        {
+            return;
+        }
+
+        UIViewRoot uiViewRoot = facesContext.getViewRoot();
+
+        if (uiViewRoot == null)
+        {
+            return;
+        }
+
+        WindowIdHolderComponent existingWindowIdHolder = getWindowIdHolderComponent(uiViewRoot);
+        if (existingWindowIdHolder != null)
+        {
+            if (!windowId.equals(existingWindowIdHolder.getWindowId()))
+            {
+                logger.log(Level.FINE, "updating WindowIdHolderComponent from %1 to %2",
+                        new Object[]{existingWindowIdHolder.getId(), windowId});
+
+                existingWindowIdHolder.changeWindowId(windowId);
+            }
+            return;
+        }
+        else
+        {
+            // add as first child
+            uiViewRoot.getChildren().add(0, new WindowIdHolderComponent(windowId));
+        }
+    }
+
+    public static WindowIdHolderComponent getWindowIdHolderComponent(UIViewRoot uiViewRoot)
+    {
+        List<UIComponent> uiComponents = uiViewRoot.getChildren();
+
+        // performance improvement - don't change - see EXTCDI-256 :
+        for (int i = 0, size = uiComponents.size(); i < size; i++)
+        {
+            UIComponent uiComponent = uiComponents.get(i);
+            if (uiComponent instanceof WindowIdHolderComponent)
+            {
+                //in this case we have the same view-root
+                return (WindowIdHolderComponent) uiComponent;
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Object saveState(FacesContext facesContext)
+    {
+        Object[] values = new Object[2];
+        values[0] = super.saveState(facesContext);
+        values[1] = windowId;
+        return values;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void restoreState(FacesContext facesContext, Object state)
+    {
+        if (state == null)
+        {
+            return;
+        }
+
+        Object[] values = (Object[]) state;
+        super.restoreState(facesContext, values[0]);
+
+        windowId = (String) values[1];
+    }
+
+    /**
+     * @return the current windowId
+     */
+    public String getWindowId()
+    {
+        return windowId;
+    }
+
+    void changeWindowId(String windowId)
+    {
+        this.windowId = windowId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdRenderKitFactory.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdRenderKitFactory.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdRenderKitFactory.java
new file mode 100644
index 0000000..883ddb0
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdRenderKitFactory.java
@@ -0,0 +1,101 @@
+/*
+ * 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;
+
+import javax.faces.context.FacesContext;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+import java.util.Iterator;
+
+import org.apache.deltaspike.core.spi.activation.Deactivatable;
+import org.apache.deltaspike.core.util.ClassDeactivationUtils;
+
+
+/**
+ * Registers the @{link WindowIdRenderKit}
+ */
+public class WindowIdRenderKitFactory extends RenderKitFactory implements Deactivatable
+{
+    private final RenderKitFactory wrapped;
+
+    private final boolean deactivated;
+
+    /**
+     * Constructor for wrapping the given {@link javax.faces.render.RenderKitFactory}
+     * @param wrapped render-kit-factory which will be wrapped
+     */
+    public WindowIdRenderKitFactory(RenderKitFactory wrapped)
+    {
+        this.wrapped = wrapped;
+        this.deactivated = !isActivated();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addRenderKit(String s, RenderKit renderKit)
+    {
+        wrapped.addRenderKit(s, renderKit);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public RenderKit getRenderKit(FacesContext facesContext, String s)
+    {
+        RenderKit renderKit = wrapped.getRenderKit(facesContext, s);
+
+        if (renderKit == null)
+        {
+            return null;
+        }
+
+        if (deactivated)
+        {
+            return renderKit;
+        }
+
+        return new WindowIdRenderKitWrapper(renderKit);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterator<String> getRenderKitIds()
+    {
+        return wrapped.getRenderKitIds();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public RenderKitFactory getWrapped()
+    {
+        return wrapped;
+    }
+
+    public boolean isActivated()
+    {
+        return ClassDeactivationUtils.isActivated(getClass());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdRenderKitWrapper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdRenderKitWrapper.java b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdRenderKitWrapper.java
new file mode 100644
index 0000000..bb939d5
--- /dev/null
+++ b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/scope/window/WindowIdRenderKitWrapper.java
@@ -0,0 +1,92 @@
+/*
+ * 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;
+
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitWrapper;
+import java.io.Writer;
+
+import org.apache.deltaspike.core.api.provider.BeanProvider;
+import org.apache.deltaspike.core.spi.scope.window.WindowContext;
+
+/**
+ * Wraps the RenderKit and adds the
+ * {@link WindowIdHolderComponent} to the view tree
+ */
+public class WindowIdRenderKitWrapper extends RenderKitWrapper
+{
+    private final RenderKit wrapped;
+
+    /**
+     * This will get initialized lazily to prevent boot order issues
+     * with the JSF and CDI containers.
+     */
+    private volatile WindowContext windowContext;
+
+
+    //needed if the renderkit gets proxied - see EXTCDI-215
+    protected WindowIdRenderKitWrapper()
+    {
+        this.wrapped = null;
+    }
+
+    public WindowIdRenderKitWrapper(RenderKit wrapped)
+    {
+        this.wrapped = wrapped;
+    }
+
+    @Override
+    public RenderKit getWrapped()
+    {
+        return wrapped;
+    }
+
+    /**
+     * Adds a {@link WindowIdHolderComponent} with the
+     * current windowId to the component tree.
+     */
+    public ResponseWriter createResponseWriter(Writer writer, String s, String s1)
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        String windowId = getWindowContext().getCurrentWindowId();
+
+        WindowIdHolderComponent.addWindowIdHolderComponent(facesContext, windowId);
+
+        return wrapped.createResponseWriter(writer, s, s1);
+    }
+
+
+    private WindowContext getWindowContext()
+    {
+        if (windowContext == null)
+        {
+            synchronized (this)
+            {
+                if (windowContext == null)
+                {
+                    windowContext = BeanProvider.getContextualReference(WindowContext.class);
+                }
+            }
+        }
+
+        return windowContext;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/30661b05/deltaspike/modules/jsf/impl/src/main/resources/META-INF/faces-config.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/impl/src/main/resources/META-INF/faces-config.xml b/deltaspike/modules/jsf/impl/src/main/resources/META-INF/faces-config.xml
index 50ed167..6d951da 100644
--- a/deltaspike/modules/jsf/impl/src/main/resources/META-INF/faces-config.xml
+++ b/deltaspike/modules/jsf/impl/src/main/resources/META-INF/faces-config.xml
@@ -36,5 +36,6 @@
     <factory>
         <lifecycle-factory>org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeLifecycleFactoryWrapper</lifecycle-factory>
         <faces-context-factory>org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeFacesContextFactory</faces-context-factory>
+        <render-kit-factory>org.apache.deltaspike.jsf.impl.scope.window.WindowIdRenderKitFactory</render-kit-factory>
     </factory>
-</faces-config>
\ No newline at end of file
+</faces-config>