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:16 UTC
[2/3] git commit: DELTASPIKE-289 add postback handling for windowId
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 @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 ?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 @Specializes this class to tweak the configuration or
+ * provide a completely new implementation as @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 ?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>