You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by de...@apache.org on 2018/05/08 12:48:05 UTC
[myfaces] 02/28: MYFACES-3588 window-id support (step 1,
implement JSF 2.2 early draft api)
This is an automated email from the ASF dual-hosted git repository.
deki pushed a commit to branch 2.1.x-client-window
in repository https://gitbox.apache.org/repos/asf/myfaces.git
commit 0b8d39d586d22b0c0fafba5b143b36e2f185726c
Author: Leonardo Uribe <lu...@apache.org>
AuthorDate: Fri Aug 3 14:33:13 2012 +0000
MYFACES-3588 window-id support (step 1, implement JSF 2.2 early draft api)
---
.../java/javax/faces/context/ExternalContext.java | 31 ++
.../faces/context/ExternalContextWrapper.java | 14 +
.../java/javax/faces/lifecycle/ClientWindow.java | 57 +++
.../main/java/javax/faces/lifecycle/Lifecycle.java | 11 +
.../javax/faces/lifecycle/LifecycleWrapper.java | 65 +++
.../javax/faces/render/ResponseStateManager.java | 3 +
.../main/java/javax/faces/webapp/FacesServlet.java | 2 +
client-window-example/pom.xml | 504 +++++++++++++++++++++
.../example/clientWindow/DisableClientWindow.java | 39 ++
.../example/clientWindow/EnableClientWindow.java | 38 ++
.../example/clientWindow/HelloWorldController.java | 64 +++
.../apache/myfaces/example/flash/FlashBean.java | 39 +-
.../myfaces/example/flash/HelloWorldFlashBean.java | 147 ++++++
.../myfaces/example/windowScope/SubKeyMap.java | 316 +++++++++++++
.../myfaces/example/windowScope/WindowScope.java | 28 ++
.../example/windowScope/WindowScopeELResolver.java | 260 +++++++++++
.../example/windowScope/WindowScopeImpl.java | 169 +++++++
.../main/webapp/META-INF/templates/example.xhtml | 38 ++
.../src/main/webapp/WEB-INF/faces-config.xml | 64 +++
.../src/main/webapp/WEB-INF/web.xml | 114 +++++
client-window-example/src/main/webapp/flash1.xhtml | 29 ++
client-window-example/src/main/webapp/flash2.xhtml | 29 ++
client-window-example/src/main/webapp/flash3.xhtml | 28 ++
.../src/main/webapp/flashKeep1.xhtml | 43 ++
.../src/main/webapp/flashKeep2.xhtml | 41 ++
.../src/main/webapp/flashKeep3.xhtml | 39 ++
.../src/main/webapp/flashKeepConfirmation.xhtml | 43 ++
.../src/main/webapp/flashKeepEntry.xhtml | 43 ++
.../src/main/webapp/flashKeepFinished.xhtml | 41 ++
.../src/main/webapp/flashg1.xhtml | 20 +
.../src/main/webapp/flashg2.xhtml | 20 +
.../src/main/webapp/flashhw1.xhtml | 26 ++
.../src/main/webapp/flashhw2.xhtml | 23 +
.../src/main/webapp/flashprg1.xhtml | 24 +
.../src/main/webapp/flashprg2.xhtml | 22 +
.../src/main/webapp/helloWorld.xhtml | 41 ++
client-window-example/src/main/webapp/home.xhtml | 59 +++
client-window-example/src/main/webapp/index.html | 24 +
client-window-example/src/main/webapp/page2.xhtml | 36 ++
.../clientWindow/disableClientWindow.xhtml | 9 +
.../clientWindow/enableClientWindow.xhtml | 9 +
.../src/main/webapp/resources/css/style.css | 33 +-
.../clientWindow/CheckFaceletsFileTestCase.java | 159 +++++++
.../src/test/resources/webapp/README.txt | 1 +
.../servlet/ServletExternalContextImpl.java | 33 +-
.../servlet/ServletExternalContextImplBase.java | 15 +
.../myfaces/lifecycle/CODIClientSideWindow.java | 424 +++++++++++++++++
.../org/apache/myfaces/lifecycle/ClientConfig.java | 241 ++++++++++
.../apache/myfaces/lifecycle/LifecycleImpl.java | 54 +++
.../apache/myfaces/lifecycle/TokenGenerator.java | 75 +++
.../apache/myfaces/lifecycle/UrlClientWindow.java | 87 ++++
.../myfaces/lifecycle/WindowContextConfig.java | 152 +++++++
.../renderkit/ServerSideStateCacheImpl.java | 45 +-
.../renderkit/html/HtmlResponseStateManager.java | 31 ++
.../myfaces/view/facelets/util/Classpath.java | 20 +-
.../org.apache.myfaces.windowId/windowhandler.html | 215 +++++++++
pom.xml | 1 +
.../myfaces/shared/context/flash/FlashImpl.java | 58 ++-
58 files changed, 4233 insertions(+), 63 deletions(-)
diff --git a/api/src/main/java/javax/faces/context/ExternalContext.java b/api/src/main/java/javax/faces/context/ExternalContext.java
index 8baab63..d1ccb17 100755
--- a/api/src/main/java/javax/faces/context/ExternalContext.java
+++ b/api/src/main/java/javax/faces/context/ExternalContext.java
@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import javax.faces.lifecycle.ClientWindow;
/**
* see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
@@ -736,4 +737,34 @@ public abstract class ExternalContext
ctx.setSessionMaxInactiveInterval(interval);
}
+
+ public ClientWindow getClientWindow()
+ {
+ ExternalContext ctx = _MyFacesExternalContextHelper.firstInstance.get();
+
+ if (ctx == null)
+ {
+ /*throw new UnsupportedOperationException();*/
+ // TODO: Return null for now, but it should throw exception
+ // in JSF 2.2
+ return null;
+ }
+
+ return ctx.getClientWindow();
+ }
+
+ public void setClientWindow(ClientWindow window)
+ {
+ // No op for now.
+ /*
+ ExternalContext ctx = _MyFacesExternalContextHelper.firstInstance.get();
+
+ if (ctx == null)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ ctx.setClientWindow(window);
+ */
+ }
}
diff --git a/api/src/main/java/javax/faces/context/ExternalContextWrapper.java b/api/src/main/java/javax/faces/context/ExternalContextWrapper.java
index 39eb7d9..929fcc4 100644
--- a/api/src/main/java/javax/faces/context/ExternalContextWrapper.java
+++ b/api/src/main/java/javax/faces/context/ExternalContextWrapper.java
@@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Set;
import javax.faces.FacesWrapper;
+import javax.faces.lifecycle.ClientWindow;
/**
* @author Simon Lessard (latest modification by $Author$)
@@ -477,4 +478,17 @@ public abstract class ExternalContextWrapper extends ExternalContext implements
{
getWrapped().setSessionMaxInactiveInterval(interval);
}
+
+ @Override
+ public ClientWindow getClientWindow()
+ {
+ return getWrapped().getClientWindow();
+ }
+
+ @Override
+ public void setClientWindow(ClientWindow window)
+ {
+ getWrapped().setClientWindow(window);
+ }
+
}
diff --git a/api/src/main/java/javax/faces/lifecycle/ClientWindow.java b/api/src/main/java/javax/faces/lifecycle/ClientWindow.java
new file mode 100644
index 0000000..d9f3796
--- /dev/null
+++ b/api/src/main/java/javax/faces/lifecycle/ClientWindow.java
@@ -0,0 +1,57 @@
+/*
+ * 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 javax.faces.lifecycle;
+
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ * @since 2.2
+ * @author Leonardo Uribe
+ */
+public abstract class ClientWindow
+{
+
+ public static final String CLIENT_WINDOW_MODE_PARAM_NAME =
+ "javax.faces.CLIENT_WINDOW_MODE";
+
+ private static final String CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED =
+ "org.apache.myfaces.CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED";
+
+ public abstract void decode(FacesContext context);
+
+ public abstract String getId();
+
+ public static boolean isClientWindowUrlQueryParameterEnabled(FacesContext context)
+ {
+ // By default is enabled, so it is easier to check the opposite.
+ return !Boolean.TRUE.equals(
+ context.getAttributes().get(CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED));
+ }
+
+ public static void disableClientWindowUrlQueryParameter(FacesContext context)
+ {
+ context.getAttributes().put(CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED, Boolean.TRUE);
+ }
+
+ public static void enableClientWindowUrlQueryParameter(FacesContext context)
+ {
+ context.getAttributes().put(CLIENT_WINDOW_URL_QUERY_PARAMETER_DISABLED, Boolean.FALSE);
+ }
+}
diff --git a/api/src/main/java/javax/faces/lifecycle/Lifecycle.java b/api/src/main/java/javax/faces/lifecycle/Lifecycle.java
index 128c616..9a60930 100755
--- a/api/src/main/java/javax/faces/lifecycle/Lifecycle.java
+++ b/api/src/main/java/javax/faces/lifecycle/Lifecycle.java
@@ -19,6 +19,7 @@
package javax.faces.lifecycle;
import javax.faces.FacesException;
+import javax.faces.context.FacesContext;
/**
* see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
@@ -39,4 +40,14 @@ public abstract class Lifecycle
public abstract void render(javax.faces.context.FacesContext context)
throws FacesException;
+
+ /**
+ *
+ * @since 2.2
+ * @param context
+ */
+ public void attachWindow(FacesContext context)
+ {
+
+ }
}
diff --git a/api/src/main/java/javax/faces/lifecycle/LifecycleWrapper.java b/api/src/main/java/javax/faces/lifecycle/LifecycleWrapper.java
new file mode 100644
index 0000000..0928673
--- /dev/null
+++ b/api/src/main/java/javax/faces/lifecycle/LifecycleWrapper.java
@@ -0,0 +1,65 @@
+/*
+ * 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 javax.faces.lifecycle;
+
+import javax.faces.FacesException;
+import javax.faces.FacesWrapper;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseListener;
+
+/**
+ *
+ * @author Leonardo Uribe
+ */
+public abstract class LifecycleWrapper extends Lifecycle implements FacesWrapper<Lifecycle>
+{
+
+ public void render(FacesContext context) throws FacesException
+ {
+ getWrapped().render(context);
+ }
+
+ public void removePhaseListener(PhaseListener listener)
+ {
+ getWrapped().removePhaseListener(listener);
+ }
+
+ public PhaseListener[] getPhaseListeners()
+ {
+ return getWrapped().getPhaseListeners();
+ }
+
+ public void execute(FacesContext context) throws FacesException
+ {
+ getWrapped().execute(context);
+ }
+
+ public void attachWindow(FacesContext context)
+ {
+ getWrapped().attachWindow(context);
+ }
+
+ public void addPhaseListener(PhaseListener listener)
+ {
+ getWrapped().addPhaseListener(listener);
+ }
+
+ public abstract LifecycleWrapper getWrapped();
+
+}
diff --git a/api/src/main/java/javax/faces/render/ResponseStateManager.java b/api/src/main/java/javax/faces/render/ResponseStateManager.java
index bed6f82..9bce04e 100755
--- a/api/src/main/java/javax/faces/render/ResponseStateManager.java
+++ b/api/src/main/java/javax/faces/render/ResponseStateManager.java
@@ -34,6 +34,9 @@ public abstract class ResponseStateManager
{
public static final String RENDER_KIT_ID_PARAM = "javax.faces.RenderKitId";
public static final String VIEW_STATE_PARAM = "javax.faces.ViewState";
+
+ public static final String CLIENT_WINDOW_PARAM = "javax.faces.ClientWindow";
+ public static final String CLIENT_WINDOW_URL_PARAM = "jfwid";
public void writeState(FacesContext context, Object state) throws IOException
{
diff --git a/api/src/main/java/javax/faces/webapp/FacesServlet.java b/api/src/main/java/javax/faces/webapp/FacesServlet.java
index 57e79e5..fb7fc37 100755
--- a/api/src/main/java/javax/faces/webapp/FacesServlet.java
+++ b/api/src/main/java/javax/faces/webapp/FacesServlet.java
@@ -192,6 +192,8 @@ public final class FacesServlet implements Servlet
}
else
{
+ //JSF 2.2: attach window
+ _lifecycle.attachWindow(facesContext);
// If this returns false, handle as follows:
// call Lifecycle.execute(javax.faces.context.FacesContext)
_lifecycle.execute(facesContext);
diff --git a/client-window-example/pom.xml b/client-window-example/pom.xml
new file mode 100644
index 0000000..71af5c9
--- /dev/null
+++ b/client-window-example/pom.xml
@@ -0,0 +1,504 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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.
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>myfaces-core-module</artifactId>
+ <groupId>org.apache.myfaces.core</groupId>
+ <version>2.1.9-CLIENT-WINDOW-SNAPSHOT</version>
+ </parent>
+ <groupId>org.apache.myfaces.example.clientWindow</groupId>
+ <artifactId>client-window-example</artifactId>
+ <packaging>war</packaging>
+ <version>2.1.9-CLIENT-WINDOW-SNAPSHOT</version>
+ <name>client-window-example</name>
+ <description>A custom project used to debug MyFaces Core 2.0</description>
+ <url>http://www.myorganization.org</url>
+
+ <!-- Instructions
+ This project uses myfaces-test and myfaces-impl test jar
+ to make easier create specific tests for myfaces core that
+ later could be included into myfaces codebase.
+ - Run using jetty
+ mvn clean jetty:run
+ mvn clean -Dcontainer=jetty-mojarra jetty:run
+ Set your browser to http://localhost:8080/client-window-example
+ - Run using tomcat
+ mvn clean -Dcontainer=tomcat7 tomcat:run
+ Set your browser to http://localhost:8080/client-window-example
+ - Run war using tomcat
+ mvn clean -Dcontainer=tomcat7 tomcat:run-war
+ Set your browser to http://localhost:8080/client-window-example
+ - Run war using jetty (remove <webApp> config inside plugin config first)
+ mvn clean jetty:run-war
+ mvn clean -Dcontainer=jetty-mojarra jetty:run-war
+ Set your browser to http://localhost:8080
+ - Build war and bundle JSF jars
+ mvn clean -Pbundle-myfaces install
+ mvn clean -Pbundle-mojarra install
+ - Run using tomcat 6.0
+ mvn clean -Dcontainer=tomcat tomcat:run-war
+ - Run using tomcat 7.0 through cargo
+ mvn clean -Dcontainer=tomcat7 install cargo:run
+ -->
+
+ <properties>
+ <jsf-myfaces.version>2.1.9-CLIENT-WINDOW-SNAPSHOT</jsf-myfaces.version>
+ <jsf-mojarra.version>2.1.7</jsf-mojarra.version>
+ <jetty.maven.plugin.version>8.1.3.v20120416</jetty.maven.plugin.version>
+ <cargo.version>1.1.1</cargo.version>
+ </properties>
+
+ <build>
+ <finalName>client-window-example</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <!-- The following plugin is used to pack everything inside
+ webapp folder and make it available on test jar under
+ the path "webapp". This allows create junit tests over
+ those files like for example, check if all facelets
+ compile, if a view is correctly built or if render
+ what is expected. -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.7</version>
+ <executions>
+ <execution>
+ <id>add-webapp-folder-as-test</id>
+ <phase>generate-test-resources</phase>
+ <goals>
+ <goal>add-test-resource</goal>
+ </goals>
+ <configuration>
+ <resources>
+ <resource>
+ <directory>src/main/webapp</directory>
+ <targetPath>webapp</targetPath>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <!-- Project dependencies -->
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-servlet_2.5_spec</artifactId>
+ <version>1.2</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-el_2.2_spec</artifactId>
+ <version>1.0.2</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-annotation_1.0_spec</artifactId>
+ <version>1.1.1</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- JSF API: Add here as provided dependency and then add it
+ on jetty-maven-plugin as compile/runtime dependency.
+ The same goes for other JSF libraries. -->
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jstl</artifactId>
+ <version>1.2</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.myfaces.test</groupId>
+ <artifactId>myfaces-test20</artifactId>
+ <version>1.0.4</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.2</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>bundle-myfaces</id>
+ <activation>
+ <property>
+ <name>jsf</name>
+ <value>myfaces</value>
+ </property>
+ </activation>
+ <!-- Include MyFaces jars into the war -->
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <!-- Plugin embedded jetty 8 container.
+ Just running use:
+ mvn clean jetty:run
+ -->
+ <!-- For debugging use (attach debugger port 8000):
+ mvnDebug clean jetty:run
+ -->
+ <id>jettyConfig</id>
+ <activation>
+ <property>
+ <name>!container</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <!--This plugin allows to run the war using mvn jetty:run -->
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <version>${jetty.maven.plugin.version}</version>
+ <configuration>
+ <systemProperties>
+ <systemProperty>
+ <!-- optional to use the ecj compiler -->
+ <name>org.apache.jasper.compiler.disablejsr199</name>
+ <value>true</value>
+ </systemProperty>
+ </systemProperties>
+ <webApp>
+ <contextPath>/${artifactId}</contextPath>
+ </webApp>
+ <scanIntervalSeconds>5</scanIntervalSeconds>
+ </configuration>
+ <dependencies>
+ <!-- Tld scanning only works when JSF is included
+ as container dependency. Add other jsf libraries
+ here, so jetty:run goal can find and process them -->
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>bundle-mojarra</id>
+ <activation>
+ <property>
+ <name>jsf</name>
+ <value>mojarra</value>
+ </property>
+ </activation>
+ <!-- Include Mojarra jars into the war -->
+ <dependencies>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>${jsf-mojarra.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>${jsf-mojarra.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ <repositories>
+ <repository>
+ <id>java.net</id>
+ <url>http://download.java.net/maven/2</url>
+ </repository>
+ </repositories>
+ </profile>
+
+ <profile>
+ <!-- Plugin embedded jetty 8 container.
+ Just running use:
+ mvn clean -Dcontainer=jetty-mojarra jetty:run
+ -->
+ <!-- For debugging use (attach debugger port 8000):
+ mvn clean -Dcontainer=jetty-mojarra jetty:run
+ -->
+ <id>jettyConfig-mojarra</id>
+ <activation>
+ <property>
+ <name>container</name>
+ <value>jetty-mojarra</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <!--This plugin allows to run the war using mvn jetty:run -->
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <version>${jetty.maven.plugin.version}</version>
+ <configuration>
+ <systemProperties>
+ <systemProperty>
+ <!-- optional to use the ecj compiler -->
+ <name>org.apache.jasper.compiler.disablejsr199</name>
+ <value>true</value>
+ </systemProperty>
+ </systemProperties>
+ <webApp>
+ <contextPath>/${artifactId}</contextPath>
+ </webApp>
+ <scanIntervalSeconds>5</scanIntervalSeconds>
+ </configuration>
+ <dependencies>
+ <!-- Tld scanning only works when JSF is included
+ as container dependency. Add other jsf libraries
+ here, so jetty:run goal can find and process them -->
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>${jsf-mojarra.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>${jsf-mojarra.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ <repositories>
+ <repository>
+ <id>java.net</id>
+ <url>http://download.java.net/maven/2</url>
+ </repository>
+ </repositories>
+ </profile>
+
+ <profile>
+ <id>maven-tomcat7</id>
+ <activation>
+ <property>
+ <name>container</name>
+ <value>tomcat7</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.tomcat.maven</groupId>
+ <artifactId>tomcat7-maven-plugin</artifactId>
+ <version>2.0-beta-1</version>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <!-- Plugin embedded tomcat 6 container.
+ Just running use:
+ mvn clean -Dcontainer=tomcat tomcat:run-war
+ -->
+ <!-- For debugging use (attach debugger port 8000):
+ mvnDebug clean -Dcontainer=tomcat tomcat:run-war
+ -->
+ <id>tomcat</id>
+ <activation>
+ <property>
+ <name>container</name>
+ <value>tomcat</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>tomcat-maven-plugin</artifactId>
+ <version>1.1</version>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <!-- Installed tomcat 7 running war file through cargo
+ Attach debugger on port 8000:
+ mvn clean -Dcontainer=tomcat7 install cargo:run -->
+ <id>cargo-tomcat7</id>
+ <activation>
+ <property>
+ <name>container</name>
+ <value>tomcat7</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.cargo</groupId>
+ <artifactId>cargo-maven2-plugin</artifactId>
+ <version>${cargo.version}</version>
+ <configuration>
+ <wait>true</wait>
+ <properties>
+ <cargo.servlet.port>8080</cargo.servlet.port>
+ <cargo.jvmargs>-Xdebug
+ -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
+ -Xnoagent
+ -Djava.compiler=NONE</cargo.jvmargs>
+ </properties>
+ <container>
+ <containerId>tomcat7x</containerId>
+ <zipUrlInstaller>
+ <url>http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.25/bin/apache-tomcat-7.0.25.zip</url>
+ <!--
+ <installDir>${basedir}/tomcat7x</installDir>
+ -->
+ <downloadDir>${basedir}/downloads</downloadDir>
+ <extractDir>${basedir}/tomcat7x</extractDir>
+ </zipUrlInstaller>
+ </container>
+ <configuration>
+ <home>${basedir}/target/tomcat7x</home>
+ <properties>
+ <cargo.jvmargs>-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -Xnoagent -Djava.compiler=NONE</cargo.jvmargs>
+ </properties>
+ </configuration>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>${jsf-myfaces.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ </profiles>
+
+</project>
diff --git a/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/DisableClientWindow.java b/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/DisableClientWindow.java
new file mode 100644
index 0000000..6f06b9a
--- /dev/null
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/DisableClientWindow.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.myfaces.example.clientWindow;
+
+import java.io.IOException;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.UINamingContainer;
+import javax.faces.context.FacesContext;
+import javax.faces.lifecycle.ClientWindow;
+
+/**
+ *
+ * @author lu4242
+ */
+@FacesComponent("oam.clientWindow.disable")
+public class DisableClientWindow extends UINamingContainer
+{
+
+ @Override
+ public void encodeBegin(FacesContext context) throws IOException
+ {
+ ClientWindow.disableClientWindowUrlQueryParameter(context);
+ super.encodeBegin(context);
+ }
+
+}
diff --git a/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/EnableClientWindow.java b/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/EnableClientWindow.java
new file mode 100644
index 0000000..c8ca66b
--- /dev/null
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/EnableClientWindow.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.myfaces.example.clientWindow;
+
+import java.io.IOException;
+import javax.faces.component.FacesComponent;
+import javax.faces.component.UINamingContainer;
+import javax.faces.context.FacesContext;
+import javax.faces.lifecycle.ClientWindow;
+
+/**
+ *
+ * @author lu4242
+ */
+@FacesComponent("oam.clientWindow.enable")
+public class EnableClientWindow extends UINamingContainer
+{
+
+ @Override
+ public void encodeBegin(FacesContext context) throws IOException
+ {
+ ClientWindow.enableClientWindowUrlQueryParameter(context);
+ super.encodeBegin(context);
+ }
+}
diff --git a/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/HelloWorldController.java b/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/HelloWorldController.java
new file mode 100644
index 0000000..28b8f57
--- /dev/null
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/clientWindow/HelloWorldController.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.example.clientWindow;
+
+import java.io.Serializable;
+import javax.faces.bean.CustomScoped;
+import javax.faces.bean.ManagedBean;
+
+/**
+ * A typical simple backing bean, that is backed to <code>helloWorld.xhtml</code>
+ */
+@ManagedBean(name = "helloWorld")
+@CustomScoped("#{window}")
+public class HelloWorldController implements Serializable
+{
+
+ //properties
+ private String name;
+
+ /**
+ * default empty constructor
+ */
+ public HelloWorldController()
+ {
+ }
+
+ /**
+ * Method that is backed to a submit button of a form.
+ */
+ public String send()
+ {
+ //do real logic, return a string which will be used for the navigation system of JSF
+ return "page2.xhtml";
+ }
+
+ //-------------------getter & setter
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+}
diff --git a/api/src/main/java/javax/faces/lifecycle/Lifecycle.java b/client-window-example/src/main/java/org/apache/myfaces/example/flash/FlashBean.java
old mode 100755
new mode 100644
similarity index 50%
copy from api/src/main/java/javax/faces/lifecycle/Lifecycle.java
copy to client-window-example/src/main/java/org/apache/myfaces/example/flash/FlashBean.java
index 128c616..378a1ad
--- a/api/src/main/java/javax/faces/lifecycle/Lifecycle.java
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/flash/FlashBean.java
@@ -15,28 +15,31 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- */
-package javax.faces.lifecycle;
+*/
+package org.apache.myfaces.example.flash;
-import javax.faces.FacesException;
+import java.awt.event.ActionEvent;
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.RequestScoped;
-/**
- * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
- *
- * @author Manfred Geiler (latest modification by $Author$)
- * @version $Revision$ $Date$
- */
-public abstract class Lifecycle
+@ManagedBean(name="flashBean")
+@RequestScoped
+public class FlashBean
{
- public abstract void addPhaseListener(javax.faces.event.PhaseListener listener);
-
- public abstract void execute(javax.faces.context.FacesContext context)
- throws FacesException;
- public abstract javax.faces.event.PhaseListener[] getPhaseListeners();
+ public String gotoFlash2()
+ {
+ return "flash2";
+ }
+
+ public String gotoFlash3()
+ {
+ return "flash3";
+ }
- public abstract void removePhaseListener(javax.faces.event.PhaseListener listener);
+ public String gotoFlash1()
+ {
+ return "flash1";
+ }
- public abstract void render(javax.faces.context.FacesContext context)
- throws FacesException;
}
diff --git a/client-window-example/src/main/java/org/apache/myfaces/example/flash/HelloWorldFlashBean.java b/client-window-example/src/main/java/org/apache/myfaces/example/flash/HelloWorldFlashBean.java
new file mode 100644
index 0000000..ba7617a
--- /dev/null
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/flash/HelloWorldFlashBean.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+package org.apache.myfaces.example.flash;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.bean.ManagedBean;
+import javax.faces.bean.RequestScoped;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.Flash;
+import javax.faces.event.PhaseEvent;
+
+/**
+ * A typical simple backing bean, that is backed to <code>helloworld.jsp</code>
+ *
+ */
+@ManagedBean(name="helloWorldFlashBean")
+@RequestScoped
+public class HelloWorldFlashBean {
+
+ //Log log = LogFactory.getLog(HelloWorldFlashBean.class);
+
+ private int before = 0;
+
+ private int after = 0;
+
+ public void beforePhase(PhaseEvent phaseEvent){
+
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ before++;
+ facesContext.addMessage(null, new FacesMessage("This is the message for phase before "+phaseEvent.getPhaseId().toString()+" : "+before+" "+facesContext.getExternalContext().getFlash().get("lastName")));
+ //log.info("This is the message for phase before "+phaseEvent.getPhaseId().toString()+" : "+before);
+ }
+
+ public void afterPhase(PhaseEvent phaseEvent){
+
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ after++;
+ facesContext.addMessage(null, new FacesMessage("This is the message for phase after "+phaseEvent.getPhaseId().toString()+" : "+after+" "+facesContext.getExternalContext().getFlash().get("lastName")));
+ //log.info("This is the message for phase after "+phaseEvent.getPhaseId().toString()+" : "+after);
+ }
+
+ //properties
+ private String name;
+
+ private String lastName;
+
+ /**
+ * default empty constructor
+ */
+ public HelloWorldFlashBean(){
+ }
+
+ //-------------------getter & setter
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLastName()
+ {
+ return lastName;
+ }
+
+ public void setLastName(String lastName)
+ {
+ this.lastName = lastName;
+ }
+
+ /**
+ * Method that is backed to a submit button of a form.
+ */
+ public String send(){
+ //do real logic, return a string which will be used for the navigation system of JSF
+
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExternalContext externalContext = facesContext.getExternalContext();
+ Flash flash = externalContext.getFlash();
+
+ flash.put("name", getName());
+ flash.setKeepMessages(true);
+ facesContext.addMessage(null, new FacesMessage("var name put on flash scope"));
+
+ return "success";
+ }
+
+ public String sendPutNow(){
+ //do real logic, return a string which will be used for the navigation system of JSF
+
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExternalContext externalContext = facesContext.getExternalContext();
+ Flash flash = externalContext.getFlash();
+
+ flash.putNow("name", getName());
+ flash.keep("name");
+ flash.setKeepMessages(true);
+ facesContext.addMessage(null, new FacesMessage("var name putNow on flash scope"));
+
+ return "success";
+ }
+
+ public String keepRedirect()
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExternalContext externalContext = facesContext.getExternalContext();
+ Flash flash = externalContext.getFlash();
+
+ flash.putNow("name", getName());
+ flash.keep("name");
+
+ return "flashKeep2.xhtml?faces-redirect=true";
+ }
+
+ public String keepPostback()
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ ExternalContext externalContext = facesContext.getExternalContext();
+ Flash flash = externalContext.getFlash();
+
+ flash.keep("name"); // does not work here anymore
+
+ return "flashKeep3.xhtml";
+ }
+
+
+ public String back(){
+ return "back";
+ }
+}
\ No newline at end of file
diff --git a/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/SubKeyMap.java b/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/SubKeyMap.java
new file mode 100644
index 0000000..a449adb
--- /dev/null
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/SubKeyMap.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.example.windowScope;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * NOTE: Class copied from trinidad to be used on FlashImpl.
+ *
+ * Map that wraps another to provide an isolated namespace using
+ * a prefix. This is especially handy for storing properties on
+ * the session in a structured manner without putting them into
+ * a true "Map" - because storing in a Map breaks session failover.
+ * (Session failover won't trigger on mutations of contained objects.)
+ * <p>
+ * Note that there is a potential design flaw; if you create a SubKeyMap
+ * for "mypackage.foo" and for "mypackage.foo.bar", all the keys in the
+ * latter will actually show up in the former (prefixed by ".bar"). This
+ * "flaw" is actually relied on by PageFlowScopeMap (since it provides
+ * a handy way to clear out all descendents), so don't "fix" it!
+ */
+final class SubKeyMap<V> extends AbstractMap<String, V>
+{
+ public SubKeyMap(Map<String, Object> base, String prefix)
+ {
+ if (base == null)
+ {
+ throw new NullPointerException();
+ }
+ if (prefix == null)
+ {
+ throw new NullPointerException();
+ }
+
+ // Optimize the scenario where we're wrapping another SubKeyMap
+ if (base instanceof SubKeyMap)
+ {
+ _base = ((SubKeyMap) base)._base;
+ _prefix = ((SubKeyMap) base)._prefix + prefix;
+ }
+ else
+ {
+ _base = base;
+ _prefix = prefix;
+ }
+ _keyBuffer = new StringBuilder(32);
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return entrySet().isEmpty();
+ }
+
+ @Override
+ public V get(Object key)
+ {
+ key = _getBaseKey(key);
+ return (V) _base.get(key);
+ }
+
+ @Override
+ public V put(String key, V value)
+ {
+ key = _getBaseKey(key);
+ return (V) _base.put(key, value);
+ }
+
+ @Override
+ public V remove(Object key)
+ {
+ key = _getBaseKey(key);
+ return (V) _base.remove(key);
+ }
+
+ @Override
+ public boolean containsKey(Object key)
+ {
+ if (!(key instanceof String))
+ {
+ return false;
+ }
+
+ return _base.containsKey(_getBaseKey(key));
+ }
+
+ @Override
+ public Set<Map.Entry<String, V>> entrySet()
+ {
+ if (_entrySet == null)
+ {
+ _entrySet = new Entries<V>();
+ }
+ return _entrySet;
+ }
+
+ private String _getBaseKey(Object key)
+ {
+ if (key == null)
+ {
+ throw new NullPointerException();
+ }
+ // Yes, I want a ClassCastException if it's not a String
+ //return _prefix + ((String) key);
+ _keyBuffer.setLength(0);
+ _keyBuffer.append(_prefix);
+ _keyBuffer.append((String) key);
+ return _keyBuffer.toString();
+ }
+
+ private List<String> _gatherKeys()
+ {
+ List<String> list = new ArrayList<String>();
+ for (String key : _base.keySet())
+ {
+ if (key != null && key.startsWith(_prefix))
+ {
+ list.add(key);
+ }
+ }
+
+ return list;
+ }
+
+ //
+ // Set implementation for SubkeyMap.entrySet()
+ //
+ private class Entries<V> extends AbstractSet<Map.Entry<String, V>>
+ {
+ public Entries()
+ {
+ }
+
+ @Override
+ public Iterator<Map.Entry<String, V>> iterator()
+ {
+ // Sadly, if you just try to use a filtering approach
+ // on the iterator, you'll get concurrent modification
+ // exceptions. Consequently, gather the keys in a list
+ // and iterator over that.
+ List<String> keyList = _gatherKeys();
+ return new EntryIterator<V>(keyList.iterator());
+ }
+
+ @Override
+ public int size()
+ {
+ int size = 0;
+ for (String key : _base.keySet())
+ {
+ if (key != null && key.startsWith(_prefix))
+ {
+ size++;
+ }
+ }
+
+ return size;
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ Iterator<String> keys = _base.keySet().iterator();
+ while (keys.hasNext())
+ {
+ String key = keys.next();
+ // Short-circuit: the default implementation would always
+ // need to iterate to find the total size.
+ if (key != null && key.startsWith(_prefix))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void clear()
+ {
+ Iterator<String> keys = _base.keySet().iterator();
+ while (keys.hasNext())
+ {
+ String key = keys.next();
+ if (key != null && key.startsWith(_prefix))
+ {
+ keys.remove();
+ }
+ }
+ }
+ }
+
+ private class EntryIterator<V> implements Iterator<Map.Entry<String, V>>
+ {
+ public EntryIterator(Iterator<String> iterator)
+ {
+ _iterator = iterator;
+ }
+
+ public boolean hasNext()
+ {
+ return _iterator.hasNext();
+ }
+
+ public Map.Entry<String, V> next()
+ {
+ String baseKey = _iterator.next();
+ _currentKey = baseKey;
+ return new Entry<V>(baseKey);
+ }
+
+ public void remove()
+ {
+ if (_currentKey == null)
+ {
+ throw new IllegalStateException();
+ }
+
+ _base.remove(_currentKey);
+
+ _currentKey = null;
+ }
+
+ private Iterator<String> _iterator;
+ private String _currentKey;
+ }
+
+ private class Entry<V> implements Map.Entry<String, V>
+ {
+ public Entry(String baseKey)
+ {
+ _baseKey = baseKey;
+ }
+
+ public String getKey()
+ {
+ if (_key == null)
+ {
+ _key = _baseKey.substring(_prefix.length());
+ }
+ return _key;
+ }
+
+ public V getValue()
+ {
+ return (V) _base.get(_baseKey);
+ }
+
+ public V setValue(V value)
+ {
+ return (V) _base.put(_baseKey, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof Map.Entry))
+ {
+ return false;
+ }
+ Map.Entry<String, V> e = (Map.Entry<String, V>) o;
+ return _equals(getKey(), e.getKey())
+ && _equals(getValue(), e.getValue());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ Object key = getKey();
+ Object value = getValue();
+ return ((key == null) ? 0 : key.hashCode())
+ ^ ((value == null) ? 0 : value.hashCode());
+ }
+
+ private String _baseKey;
+ private String _key;
+ }
+
+ static private boolean _equals(Object a, Object b)
+ {
+ if (a == null)
+ {
+ return b == null;
+ }
+ return a.equals(b);
+ }
+
+ private final Map<String, Object> _base;
+ private final String _prefix;
+ private Set<Map.Entry<String, V>> _entrySet;
+ private StringBuilder _keyBuffer;
+
+}
diff --git a/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScope.java b/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScope.java
new file mode 100644
index 0000000..9b7db01
--- /dev/null
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScope.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.myfaces.example.windowScope;
+
+import java.util.Map;
+
+/**
+ *
+ * @author lu4242
+ */
+public abstract class WindowScope implements Map<String, Object>
+{
+
+
+}
diff --git a/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScopeELResolver.java b/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScopeELResolver.java
new file mode 100644
index 0000000..df91837
--- /dev/null
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScopeELResolver.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.myfaces.example.windowScope;
+
+import java.beans.FeatureDescriptor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.PropertyNotFoundException;
+import javax.el.PropertyNotWritableException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ * @author lu4242
+ */
+public class WindowScopeELResolver extends ELResolver
+{
+ public static final String WINDOW = "window";
+
+ @Override
+ public void setValue(final ELContext context, final Object base, final Object property, final Object value)
+ {
+ if (property == null)
+ {
+ throw new PropertyNotFoundException();
+ }
+ if (!(property instanceof String))
+ {
+ return;
+ }
+
+ String strProperty = property.toString();
+
+ if (WINDOW.equals(strProperty))
+ {
+ throw new PropertyNotWritableException();
+ }
+ else if (base instanceof WindowScope)
+ {
+ context.setPropertyResolved(true);
+ try
+ {
+ ((WindowScope) base).put(strProperty, value);
+ }
+ catch (UnsupportedOperationException e)
+ {
+ throw new PropertyNotWritableException(e);
+ }
+ }
+ }
+
+ @Override
+ public boolean isReadOnly(ELContext context, Object base, Object property)
+ throws NullPointerException, PropertyNotFoundException, ELException
+ {
+
+ if (property == null)
+ {
+ throw new PropertyNotFoundException();
+ }
+ if (!(property instanceof String))
+ {
+ return false;
+ }
+
+ String strProperty = property.toString();
+
+ if (WINDOW.equals(strProperty))
+ {
+ context.setPropertyResolved(true);
+ return true;
+ }
+ else if (base instanceof WindowScope)
+ {
+ context.setPropertyResolved(true);
+ }
+
+ return false;
+ }
+
+ @Override
+ public Object getValue(ELContext elContext, Object base, Object property)
+ throws NullPointerException, PropertyNotFoundException, ELException
+ {
+
+ if (property == null)
+ {
+ throw new PropertyNotFoundException();
+ }
+ if (!(property instanceof String))
+ {
+ return null;
+ }
+
+ String strProperty = property.toString();
+
+ if (base == null)
+ {
+ if (WINDOW.equals(strProperty))
+ {
+ FacesContext facesContext = facesContext(elContext);
+ if (facesContext == null)
+ {
+ return null;
+ }
+ ExternalContext externalContext = facesContext.getExternalContext();
+ if (externalContext == null)
+ {
+ return null;
+ }
+
+ //Access to window object
+ elContext.setPropertyResolved(true);
+ WindowScope window = getScope(facesContext);
+
+ return window;
+ }
+ }
+ else if (base instanceof WindowScope)
+ {
+ FacesContext facesContext = facesContext(elContext);
+ if (facesContext == null)
+ {
+ return null;
+ }
+ ExternalContext externalContext = facesContext.getExternalContext();
+ if (externalContext == null)
+ {
+ return null;
+ }
+ WindowScope window = (WindowScope) base;
+ //Just get the value
+ elContext.setPropertyResolved(true);
+ return window.get(strProperty);
+ }
+ return null;
+ }
+
+ // get the FacesContext from the ELContext
+ protected FacesContext facesContext(ELContext context)
+ {
+ return (FacesContext) context.getContext(FacesContext.class);
+ }
+
+ protected ExternalContext externalContext(ELContext context)
+ {
+ return facesContext(context).getExternalContext();
+ }
+
+ private WindowScope getScope(final FacesContext facesContext)
+ {
+ return WindowScopeImpl.getCurrentInstance(facesContext.getExternalContext());
+ }
+
+ @Override
+ public Class<?> getType(ELContext context, Object base, Object property)
+ throws NullPointerException, PropertyNotFoundException, ELException
+ {
+
+ if (property == null)
+ {
+ throw new PropertyNotFoundException();
+ }
+ if (!(property instanceof String))
+ {
+ return null;
+ }
+
+ String strProperty = property.toString();
+
+ if (WINDOW.equals(strProperty))
+ {
+ context.setPropertyResolved(true);
+ }
+ else if (base instanceof WindowScope)
+ {
+ context.setPropertyResolved(true);
+ Object obj = ((WindowScope) base).get(property);
+ return (obj != null) ? obj.getClass() : null;
+ }
+
+ return null;
+ }
+
+ @Override
+ public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context,
+ Object base)
+ {
+ ArrayList<FeatureDescriptor> descriptors = new ArrayList<FeatureDescriptor>(1);
+
+ descriptors.add(makeDescriptor(WINDOW,
+ "Represents the current flash scope", Object.class));
+
+ if (base instanceof WindowScope)
+ {
+ Iterator itr = ((WindowScope) base).keySet().iterator();
+ Object key;
+ FeatureDescriptor desc;
+ while (itr.hasNext())
+ {
+ key = itr.next();
+ desc = makeDescriptor(key.toString(), key.toString(), key.getClass());
+ descriptors.add(desc);
+ }
+ }
+ return descriptors.iterator();
+ }
+
+ protected FeatureDescriptor makeDescriptor(String name, String description,
+ Class<?> elResolverType)
+ {
+ FeatureDescriptor fd = new FeatureDescriptor();
+ fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE);
+ fd.setValue(ELResolver.TYPE, elResolverType);
+ fd.setName(name);
+ fd.setDisplayName(name);
+ fd.setShortDescription(description);
+ fd.setExpert(false);
+ fd.setHidden(false);
+ fd.setPreferred(true);
+ return fd;
+ }
+
+ @Override
+ public Class<?> getCommonPropertyType(ELContext context, Object base)
+ {
+ if (base == null)
+ {
+ return null;
+ }
+
+ if (base instanceof WindowScope)
+ {
+ return Object.class;
+ }
+ else if (WINDOW.equals(base.toString()))
+ {
+ return Object.class;
+ }
+
+ return null;
+ }
+}
diff --git a/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScopeImpl.java b/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScopeImpl.java
new file mode 100644
index 0000000..f42c01a
--- /dev/null
+++ b/client-window-example/src/main/java/org/apache/myfaces/example/windowScope/WindowScopeImpl.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.myfaces.example.windowScope;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+/**
+ *
+ * @author lu4242
+ */
+public class WindowScopeImpl extends WindowScope
+{
+
+ private static final String WINDOW_PREFIX = "oam.Window";
+
+ /**
+ * Key for the cached render FlashMap instance on the request map.
+ */
+ static final String WINDOW_MAP = WINDOW_PREFIX + ".WINDOWMAP";
+
+ /**
+ * Key on application map to keep current instance
+ */
+ static final String WINDOW_INSTANCE = WINDOW_PREFIX + ".INSTANCE";
+
+ /**
+ * Session map prefix to flash maps
+ */
+ static final String WINDOW_SESSION_MAP_SUBKEY_PREFIX = WINDOW_PREFIX + ".SCOPE";
+
+ /**
+ * Token separator.
+ */
+ static final char SEPARATOR_CHAR = '.';
+
+ public WindowScopeImpl(ExternalContext externalContext)
+ {
+
+ }
+
+ public int size()
+ {
+ return getActiveWindowScopeMap().size();
+ }
+
+ public boolean isEmpty()
+ {
+ return getActiveWindowScopeMap().isEmpty();
+ }
+
+ public boolean containsKey(Object key)
+ {
+ return getActiveWindowScopeMap().containsKey(key);
+ }
+
+ public boolean containsValue(Object value)
+ {
+ return getActiveWindowScopeMap().containsValue(value);
+ }
+
+ public Object get(Object key)
+ {
+ return getActiveWindowScopeMap().get(key);
+ }
+
+ public Object put(String key, Object value)
+ {
+ return getActiveWindowScopeMap().put(key, value);
+ }
+
+ public Object remove(Object key)
+ {
+ return getActiveWindowScopeMap().remove(key);
+ }
+
+ public void putAll(Map<? extends String, ? extends Object> m)
+ {
+ getActiveWindowScopeMap().putAll(m);
+ }
+
+ public void clear()
+ {
+ getActiveWindowScopeMap().clear();
+ }
+
+ public Set<String> keySet()
+ {
+ return getActiveWindowScopeMap().keySet();
+ }
+
+ public Collection<Object> values()
+ {
+ return getActiveWindowScopeMap().values();
+ }
+
+ public Set<Entry<String, Object>> entrySet()
+ {
+ return getActiveWindowScopeMap().entrySet();
+ }
+
+ private Map<String, Object> getActiveWindowScopeMap()
+ {
+ FacesContext context = FacesContext.getCurrentInstance();
+ Map<Object, Object> requestMap = context.getAttributes();
+ Map<String, Object> map = (Map<String, Object>) requestMap.get(WINDOW_MAP);
+ if (map == null)
+ {
+ String token = (String) context.getExternalContext().getClientWindow().getId();
+ String fullToken = WINDOW_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + token;
+ map = _createSubKeyMap(context, fullToken);
+ requestMap.put(WINDOW_MAP, map);
+ }
+ return map;
+ }
+
+ /**
+ * Create a new subkey-wrapper of the session map with the given prefix.
+ * This wrapper is used to implement the maps for the flash scope.
+ * For more information see the SubKeyMap doc.
+ */
+ private Map<String, Object> _createSubKeyMap(FacesContext context, String prefix)
+ {
+ ExternalContext external = context.getExternalContext();
+ Map<String, Object> sessionMap = external.getSessionMap();
+
+ return new SubKeyMap<Object>(sessionMap, prefix);
+ }
+
+ public static WindowScope getCurrentInstance(ExternalContext context)
+ {
+ Map<String, Object> applicationMap = context.getApplicationMap();
+
+ WindowScope flash = (WindowScope) applicationMap.get(WINDOW_INSTANCE);
+ if (flash == null)
+ {
+ // synchronize the ApplicationMap to ensure that only
+ // once instance of FlashImpl is created and stored in it.
+ synchronized (applicationMap)
+ {
+ // check again, because first try was un-synchronized
+ flash = (WindowScope) applicationMap.get(WINDOW_INSTANCE);
+ if (flash == null)
+ {
+ flash = new WindowScopeImpl(context);
+ applicationMap.put(WINDOW_INSTANCE, flash);
+ }
+ }
+ }
+
+ return flash;
+ }
+}
diff --git a/client-window-example/src/main/webapp/META-INF/templates/example.xhtml b/client-window-example/src/main/webapp/META-INF/templates/example.xhtml
new file mode 100644
index 0000000..595168b
--- /dev/null
+++ b/client-window-example/src/main/webapp/META-INF/templates/example.xhtml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<h:head>
+ <title>Hello World</title>
+</h:head>
+<h:body>
+ <h:outputStylesheet name="style.css" library="css"/>
+ <div id="container">
+ <ui:insert name="container"/>
+ <br/>
+ <br/>
+ <h:link outcome="home" value="Index"/>
+ </div>
+</h:body>
+</html>
diff --git a/client-window-example/src/main/webapp/WEB-INF/faces-config.xml b/client-window-example/src/main/webapp/WEB-INF/faces-config.xml
new file mode 100644
index 0000000..4c57112
--- /dev/null
+++ b/client-window-example/src/main/webapp/WEB-INF/faces-config.xml
@@ -0,0 +1,64 @@
+<?xml version="1.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.
+-->
+<faces-config version="2.0"
+ xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
+
+ <application>
+ <el-resolver>org.apache.myfaces.example.windowScope.WindowScopeELResolver</el-resolver>
+ </application>
+
+ <!-- navigation rules for helloWorld flash post-redirect-get pattern -->
+ <navigation-rule>
+ <from-view-id>/flashprg1.xhtml</from-view-id>
+ <navigation-case>
+ <from-outcome>success</from-outcome>
+ <to-view-id>/flashprg2.xhtml</to-view-id>
+ <redirect/>
+ </navigation-case>
+ </navigation-rule>
+ <navigation-rule>
+ <from-view-id>/flashprg2.xhtml</from-view-id>
+ <navigation-case>
+ <from-outcome>back</from-outcome>
+ <to-view-id>/flashprg1.xhtml</to-view-id>
+ </navigation-case>
+ </navigation-rule>
+
+ <!-- navigation rules for helloWorld flash using putNow/keep method to keep previous name -->
+ <navigation-rule>
+ <from-view-id>/flashhw1.xhtml</from-view-id>
+ <navigation-case>
+ <from-outcome>success</from-outcome>
+ <to-view-id>/flashhw2.xhtml</to-view-id>
+ </navigation-case>
+ </navigation-rule>
+ <navigation-rule>
+ <from-view-id>/flashhw2.xhtml</from-view-id>
+ <navigation-case>
+ <from-outcome>back</from-outcome>
+ <to-view-id>/flashhw1.xhtml</to-view-id>
+ </navigation-case>
+ </navigation-rule>
+
+</faces-config>
+
\ No newline at end of file
diff --git a/client-window-example/src/main/webapp/WEB-INF/web.xml b/client-window-example/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..75eb376
--- /dev/null
+++ b/client-window-example/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,114 @@
+<?xml version="1.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.
+-->
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+ version="2.5">
+
+ <description>MyProject web.xml</description>
+
+ <!-- JSF standard parameters -->
+ <context-param>
+ <description>Project stage for the application (new in 2.0). Expects one of
+ the following values: Development, Production, SystemTest, UnitTest
+ </description>
+ <param-name>javax.faces.PROJECT_STAGE</param-name>
+ <param-value>Development</param-value>
+ </context-param>
+ <context-param>
+ <description>
+ If this parameter is set to true and the submitted value of a component is
+ the empty string, the submitted value will be set to null
+ </description>
+ <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
+ <param-value>true</param-value>
+ </context-param>
+ <context-param>
+ <description>Define the state method to be used. There are two different options
+ defined by the specification: 'client' and 'server' state.</description>
+ <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
+ <param-value>server</param-value>
+ </context-param>
+ <context-param>
+ <param-name>javax.faces.CLIENT_WINDOW_MODE</param-name>
+ <param-value>default</param-value>
+ </context-param>
+
+ <!-- MyFaces specific parameters -->
+ <!-- See http://myfaces.apache.org/docindex.html for documentation
+ about MyFaces Projects -->
+ <!-- See http://myfaces.apache.org/core21/myfaces-impl/webconfig.html
+ for an updated list of web config parameters for MyFaces Core
+ See http://wiki.apache.org/myfaces/Secure_Your_Application
+ for instructions about how to secure your web application -->
+ <context-param>
+ <description>Only applicable if state saving method is "server" (= default).
+ Defines the amount (default = 20) of the latest views are stored in session.</description>
+ <param-name>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</param-name>
+ <param-value>2</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION</param-name>
+ <param-value>1</param-value>
+ </context-param>
+ <context-param>
+ <description>Only applicable if state saving method is "server" (= default).
+ If true (default) the state will be serialized to a byte stream before it
+ is written to the session.
+ If false the state will not be serialized to a byte stream.</description>
+ <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
+ <param-value>false</param-value>
+ </context-param>
+ <context-param>
+ <description>Only applicable if state saving method is "server" (= default) and if
+ org.apache.myfaces.SERIALIZE_STATE_IN_SESSION is true (= default)
+ If true (default) the serialized state will be compressed before it
+ is written to the session. If false the state will not be compressed.</description>
+ <param-name>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</param-name>
+ <param-value>false</param-value>
+ </context-param>
+ <context-param>
+ <description>Defines which packages to scan for beans, separated by commas.
+ Useful for when using maven and jetty:run (version 6) or tomcat:run
+ </description>
+ <param-name>org.apache.myfaces.annotation.SCAN_PACKAGES</param-name>
+ <param-value>org.apache.myfaces.example</param-value>
+ </context-param>
+
+ <!-- Faces Servlet -->
+ <servlet>
+ <servlet-name>Faces Servlet</servlet-name>
+ <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <!-- Faces Servlet Mapping -->
+ <servlet-mapping>
+ <servlet-name>Faces Servlet</servlet-name>
+ <url-pattern>*.jsf</url-pattern>
+ </servlet-mapping>
+
+ <!-- Welcome files -->
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ </welcome-file-list>
+
+</web-app>
diff --git a/client-window-example/src/main/webapp/flash1.xhtml b/client-window-example/src/main/webapp/flash1.xhtml
new file mode 100644
index 0000000..9a5edab
--- /dev/null
+++ b/client-window-example/src/main/webapp/flash1.xhtml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h:outputText value="Flash 1"/>
+ <h:panelGrid columns="2">
+ <c:set target="${flash}" property="testProperty1" value="fooValue" />
+ <h:outputLabel value="testProperty1" for="tp1" />
+ <h:outputText id="tp1" value="#{flash.testProperty1}"/>
+ <h:outputLabel value="testProperty2" for="tp2" />
+ <h:outputText id="tp2" value="#{flash.testProperty2}"/>
+ <h:commandButton value="Go to flash2.jsp" action="#{flashBean.gotoFlash2}"></h:commandButton>
+ <h:messages showDetail="true" showSummary="false"/>
+ </h:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flash2.xhtml b/client-window-example/src/main/webapp/flash2.xhtml
new file mode 100644
index 0000000..dfab4d4
--- /dev/null
+++ b/client-window-example/src/main/webapp/flash2.xhtml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h:outputText value="Flash 2"/>
+ <c:set target="${flash}" property="testProperty2" value="fooValue2" />
+ <h:panelGrid columns="2">
+ <h:outputLabel value="testProperty1" for="tp1" />
+ <h:outputText id="tp1" value="#{flash.testProperty1}"/>
+ <h:outputLabel value="testProperty2" for="tp2" />
+ <h:outputText id="tp2" value="#{flash.testProperty2}"/>
+ <h:commandButton value="Go to flash3.jsp" action="#{flashBean.gotoFlash3}"/>
+ <h:messages showDetail="true" showSummary="false"/>
+ </h:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flash3.xhtml b/client-window-example/src/main/webapp/flash3.xhtml
new file mode 100644
index 0000000..4b95136
--- /dev/null
+++ b/client-window-example/src/main/webapp/flash3.xhtml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h:outputText value="Flash 3"/>
+ <h:panelGrid columns="2">
+ <h:outputLabel value="testProperty1" for="tp1" />
+ <h:outputText id="tp1" value="#{flash.testProperty1}"/>
+ <h:outputLabel value="testProperty2" for="tp2" />
+ <h:outputText id="tp2" value="#{flash.testProperty2}"/>
+ <h:commandButton value="Go to flash1.jsp" action="#{flashBean.gotoFlash1}"/>
+ <h:messages showDetail="true" showSummary="false"/>
+ </h:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashKeep1.xhtml b/client-window-example/src/main/webapp/flashKeep1.xhtml
new file mode 100644
index 0000000..5fe15b4
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashKeep1.xhtml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h3><h:outputText value="Flash Keep" /></h3>
+ <h:panelGrid columns="2">
+ <h:outputLabel value="Name" for="name" />
+ <h:inputText id="name" value="#{helloWorldFlashBean.name}" />
+ </h:panelGrid>
+ <h:commandButton action="#{helloWorldFlashBean.keepRedirect}"
+ value="Keep over Redirect" />
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashKeep2.xhtml b/client-window-example/src/main/webapp/flashKeep2.xhtml
new file mode 100644
index 0000000..e5ac430
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashKeep2.xhtml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h3><h:outputText value="Flash Keep" /></h3>
+
+ Your name is: #{flash.name} <br/>
+ <h:commandButton action="#{helloWorldFlashBean.keepPostback}"
+ value="Do another postback" />
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashKeep3.xhtml b/client-window-example/src/main/webapp/flashKeep3.xhtml
new file mode 100644
index 0000000..7015508
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashKeep3.xhtml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h3><h:outputText value="Flash Keep" /></h3>
+
+ This is now empty: #{flash.name}
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashKeepConfirmation.xhtml b/client-window-example/src/main/webapp/flashKeepConfirmation.xhtml
new file mode 100644
index 0000000..02be36d
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashKeepConfirmation.xhtml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h3><h:outputText value="Flash Keep With Redirect (Confirmation)" /></h3>
+ <h:panelGrid columns="2">
+ <h:outputLabel value="Name" for="name" />
+ <h:outputText id="name" value="#{flash.keep.name}" />
+ </h:panelGrid>
+ <h:commandButton value="Confirm"
+ action="flashKeepFinished?faces-redirect=true"/>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashKeepEntry.xhtml b/client-window-example/src/main/webapp/flashKeepEntry.xhtml
new file mode 100644
index 0000000..a5a6087
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashKeepEntry.xhtml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h3><h:outputText value="Flash Keep With Redirect (Entry)" /></h3>
+ <h:panelGrid columns="2">
+ <h:outputLabel value="Name" for="name" />
+ <h:inputText id="name" value="#{flash.name}" />
+ </h:panelGrid>
+ <h:commandButton value="Submit"
+ action="flashKeepConfirmation?faces-redirect=true"/>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashKeepFinished.xhtml b/client-window-example/src/main/webapp/flashKeepFinished.xhtml
new file mode 100644
index 0000000..16e3c03
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashKeepFinished.xhtml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h3><h:outputText value="Flash Keep With Redirect (Finished)" /></h3>
+ <h:panelGrid columns="2">
+ <h:outputLabel value="Name" for="name" />
+ <h:outputText id="name" value="#{flash.keep.name}" />
+ </h:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashg1.xhtml b/client-window-example/src/main/webapp/flashg1.xhtml
new file mode 100644
index 0000000..3be46fc
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashg1.xhtml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <c:set target="#{flash}" property="name" value="Michi (from 1)"/>
+ <h:outputText value="#{flash.name}"/>
+ <h:link outcome="flashg2" value="to page2"/>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashg2.xhtml b/client-window-example/src/main/webapp/flashg2.xhtml
new file mode 100644
index 0000000..6a37aa2
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashg2.xhtml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:c="http://java.sun.com/jsp/jstl/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <c:set target="#{flash}" property="name" value="Michi (from 2)"/>
+ <h:outputText value="#{flash.name}"/>
+ <h:link outcome="flashg1" value="to page1"/>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashhw1.xhtml b/client-window-example/src/main/webapp/flashhw1.xhtml
new file mode 100644
index 0000000..891a49f
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashhw1.xhtml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h:panelGrid columns="2">
+ <h:outputLabel for="name" value="Please enter your name" />
+ <h:inputText id="name" value="#{helloWorldFlashBean.name}" required="true"/>
+ <h:outputLabel for="pname" value="Previous name" />
+ <h:outputText id="pname" value="#{flash.name}"/>
+ <h:commandButton value="Press me" action="#{helloWorldFlashBean.sendPutNow}"/>
+ <h:messages showDetail="true" showSummary="false"/>
+ </h:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashhw2.xhtml b/client-window-example/src/main/webapp/flashhw2.xhtml
new file mode 100644
index 0000000..14874ad
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashhw2.xhtml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h2><h:outputText value="Hello #{helloWorldFlashBean.name}. Flash name should appear next request (press back)"/></h2>
+ <h:messages showDetail="true" showSummary="false"/>
+ <h:commandLink action="back">
+ <h:outputText value="Home"/>
+ </h:commandLink>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
\ No newline at end of file
diff --git a/client-window-example/src/main/webapp/flashprg1.xhtml b/client-window-example/src/main/webapp/flashprg1.xhtml
new file mode 100644
index 0000000..95aa0d1
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashprg1.xhtml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>Myfaces Examples</h1>
+ <h:form id="mainForm">
+ <h:panelGrid columns="2">
+ <h:outputLabel for="name" value="Please enter your name" />
+ <h:inputText id="name" value="#{helloWorldFlashBean.name}" required="true"/>
+ <h:commandButton value="Press me" action="#{helloWorldFlashBean.send}"/>
+ <h:messages showDetail="true" showSummary="false"/>
+ </h:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/flashprg2.xhtml b/client-window-example/src/main/webapp/flashprg2.xhtml
new file mode 100644
index 0000000..22652b5
--- /dev/null
+++ b/client-window-example/src/main/webapp/flashprg2.xhtml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets"
+ >
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h:form id="mainForm">
+ <h2><h:outputText value="Hello #{flash.name}. We hope you enjoy Apache MyFaces"/></h2>
+ <h:messages showDetail="true" showSummary="false"/>
+ <h:commandLink action="#{helloWorldFlashBean.back}">
+ <h:outputText value="Home"/>
+ </h:commandLink>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
\ No newline at end of file
diff --git a/client-window-example/src/main/webapp/helloWorld.xhtml b/client-window-example/src/main/webapp/helloWorld.xhtml
new file mode 100644
index 0000000..b3da4ee
--- /dev/null
+++ b/client-window-example/src/main/webapp/helloWorld.xhtml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>MyFaces Hello World</h1>
+ <h:form id="mainForm">
+ <h:panelGrid columns="2">
+ <h:outputLabel for="name" value="Please enter your name"/>
+ <h:inputText id="name" value="#{helloWorld.name}" required="true"/>
+ <h:commandButton value="Press me" action="#{helloWorld.send}"/>
+ <h:messages showDetail="true" showSummary="false"/>
+ </h:panelGrid>
+ </h:form>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/home.xhtml b/client-window-example/src/main/webapp/home.xhtml
new file mode 100644
index 0000000..f4325a2
--- /dev/null
+++ b/client-window-example/src/main/webapp/home.xhtml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:cw="http://java.sun.com/jsf/composite/clientWindow">
+<h:head>
+ <title>Hello World</title>
+</h:head>
+<h:body>
+ <h:outputStylesheet name="style.css" library="css"/>
+ <div id="container">
+ <h1>MyFaces Hello World</h1>
+
+ <h:panelGrid columns="1">
+
+ <h:link outcome="helloWorld" value="helloWorld"/>
+
+ <h:panelGroup>
+ <cw:disableClientWindow/>
+ <h:link outcome="helloWorld" value="helloWorld (do not append url param and set target=''blank'')" target="_blank"/>
+ <cw:enableClientWindow/>
+ </h:panelGroup>
+
+ <h:link outcome="flash1" value="Flash"/>
+
+ <h:link outcome="flashKeep1" value="Flash Keep"/>
+
+ <h:link outcome="flashKeepEntry" value="Flash Keep Entry"/>
+
+ <h:link outcome="flashg1" value="Flash using c:set"/>
+
+ <h:link outcome="flashhw1" value="HelloWorld using Flash"/>
+
+ <h:link outcome="flashprg1" value="Flash in POST-REDIRECT-GET"/>
+
+ </h:panelGrid>
+ </div>
+</h:body>
+</html>
diff --git a/client-window-example/src/main/webapp/index.html b/client-window-example/src/main/webapp/index.html
new file mode 100644
index 0000000..d53f072
--- /dev/null
+++ b/client-window-example/src/main/webapp/index.html
@@ -0,0 +1,24 @@
+<!--
+ 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>
+ <meta http-equiv="refresh" content="0; URL=home.jsf">
+</head>
+</html>
+
diff --git a/client-window-example/src/main/webapp/page2.xhtml b/client-window-example/src/main/webapp/page2.xhtml
new file mode 100644
index 0000000..d248aa7
--- /dev/null
+++ b/client-window-example/src/main/webapp/page2.xhtml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:ui="http://java.sun.com/jsf/facelets">
+<body>
+<ui:composition template="/META-INF/templates/example.xhtml">
+ <ui:define name="container">
+ <h1>MyFaces Hello World</h1>
+ <h:outputText value="Hello #{helloWorld.name}. We hope you enjoy Apache MyFaces!"/>
+ <br/>
+ <h:link value="Home" outcome="helloWorld"/>
+ </ui:define>
+</ui:composition>
+</body>
+</html>
diff --git a/client-window-example/src/main/webapp/resources/clientWindow/disableClientWindow.xhtml b/client-window-example/src/main/webapp/resources/clientWindow/disableClientWindow.xhtml
new file mode 100644
index 0000000..b662ed4
--- /dev/null
+++ b/client-window-example/src/main/webapp/resources/clientWindow/disableClientWindow.xhtml
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:cc="http://java.sun.com/jsf/composite">
+ <cc:interface componentType="oam.clientWindow.disable">
+ </cc:interface>
+ <cc:implementation>
+ </cc:implementation>
+</html>
\ No newline at end of file
diff --git a/client-window-example/src/main/webapp/resources/clientWindow/enableClientWindow.xhtml b/client-window-example/src/main/webapp/resources/clientWindow/enableClientWindow.xhtml
new file mode 100644
index 0000000..f2cdee9
--- /dev/null
+++ b/client-window-example/src/main/webapp/resources/clientWindow/enableClientWindow.xhtml
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:cc="http://java.sun.com/jsf/composite">
+ <cc:interface componentType="oam.clientWindow.enable">
+ </cc:interface>
+ <cc:implementation>
+ </cc:implementation>
+</html>
\ No newline at end of file
diff --git a/api/src/main/java/javax/faces/lifecycle/Lifecycle.java b/client-window-example/src/main/webapp/resources/css/style.css
old mode 100755
new mode 100644
similarity index 50%
copy from api/src/main/java/javax/faces/lifecycle/Lifecycle.java
copy to client-window-example/src/main/webapp/resources/css/style.css
index 128c616..5d1ec09
--- a/api/src/main/java/javax/faces/lifecycle/Lifecycle.java
+++ b/client-window-example/src/main/webapp/resources/css/style.css
@@ -16,27 +16,20 @@
* specific language governing permissions and limitations
* under the License.
*/
-package javax.faces.lifecycle;
-import javax.faces.FacesException;
-
-/**
- * see Javadoc of <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>
- *
- * @author Manfred Geiler (latest modification by $Author$)
- * @version $Revision$ $Date$
- */
-public abstract class Lifecycle
-{
- public abstract void addPhaseListener(javax.faces.event.PhaseListener listener);
-
- public abstract void execute(javax.faces.context.FacesContext context)
- throws FacesException;
-
- public abstract javax.faces.event.PhaseListener[] getPhaseListeners();
+body {
+ background-color: rgb(0, 35, 75);
+ font-family: tahoma, arial, helvetica, sans-serif;
+ font-size: 12px;
+}
- public abstract void removePhaseListener(javax.faces.event.PhaseListener listener);
+#container {
+ margin: 10px auto;
+ width: 900px;
+ background-color: white;
+ padding: 3px;
+}
- public abstract void render(javax.faces.context.FacesContext context)
- throws FacesException;
+h1 {
+ font-size: 20px;
}
diff --git a/client-window-example/src/test/java/org/apache/myfaces/example/clientWindow/CheckFaceletsFileTestCase.java b/client-window-example/src/test/java/org/apache/myfaces/example/clientWindow/CheckFaceletsFileTestCase.java
new file mode 100644
index 0000000..4e741df
--- /dev/null
+++ b/client-window-example/src/test/java/org/apache/myfaces/example/clientWindow/CheckFaceletsFileTestCase.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.example.clientWindow;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ResponseWriter;
+import org.apache.myfaces.shared.config.MyfacesConfig;
+
+import org.apache.myfaces.view.facelets.FaceletFactory;
+import org.apache.myfaces.view.facelets.FaceletTestCase;
+import org.apache.myfaces.view.facelets.compiler.Compiler;
+import org.apache.myfaces.view.facelets.util.FastWriter;
+import org.junit.Test;
+
+public class CheckFaceletsFileTestCase extends FaceletTestCase
+{
+
+ @Override
+ protected void setUpServletObjects() throws Exception
+ {
+ super.setUpServletObjects();
+ servletContext.addInitParameter("org.apache.myfaces.annotation.SCAN_PACKAGES",
+ "org.apache.myfaces.example");
+
+ }
+ /**
+ * Check all .xhtml can be parsed by facelets compiler
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testCanCompileFaceletFiles() throws Exception
+ {
+ Compiler compiler = vdl.createCompiler(facesContext);
+ FaceletFactory factory = vdl.createFaceletFactory(facesContext, compiler);
+
+ checkFaceletsFiles(factory, "/");
+ }
+
+ private void checkFaceletsFiles(FaceletFactory factory, String pathBase) throws Exception
+ {
+ Set<String> paths = externalContext.getResourcePaths(pathBase);
+ for (String path : paths)
+ {
+ if (path.endsWith(".xhtml"))
+ {
+ factory.getFacelet(getLocalFile(path.substring(1)));
+ }
+ else if (path.endsWith("/"))
+ {
+ checkFaceletsFiles(factory, path);
+ }
+ }
+ }
+
+
+ /**
+ * Check a if a single view can be built.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testSingleFaceletsFile() throws Exception {
+ //Step 1: initialize beans
+
+ //Step 2: build view
+ UIViewRoot root = facesContext.getViewRoot();
+ vdl.buildView(facesContext, root, "helloWorld.xhtml");
+
+ //Step 3: render view
+ FastWriter fw = new FastWriter();
+ ResponseWriter rw = facesContext.getResponseWriter();
+ rw = rw.cloneWithWriter(fw);
+ facesContext.setResponseWriter(rw);
+ root.encodeAll(facesContext);
+ //System.out.println(fw);
+ }
+
+ @Test
+ public void testCanBuildViews() throws Exception {
+ //Step 1: initialize beans
+ /*
+ List<String> viewPaths = new ArrayList<String>();
+
+ Set<String> paths = externalContext.getResourcePaths("/");
+
+ for (String path : paths)
+ {
+ // Those places are used to hold templates and composite components,
+ // ignore them.
+ if (path.startsWith("/META-INF") ||
+ path.startsWith("/WEB-INF") ||
+ path.startsWith("/resources"))
+ {
+ continue;
+ }
+ else if (path.endsWith(".xhtml"))
+ {
+ viewPaths.add(path);
+ }
+ else if (path.endsWith("/"))
+ {
+ addViewFacelets(viewPaths, path);
+ }
+ }
+
+ //Step 2: build view
+ for (String viewPath : viewPaths)
+ {
+ UIViewRoot root = application.getViewHandler().createView(facesContext, viewPath);
+ facesContext.setViewRoot(root);
+ vdl.buildView(facesContext, root, viewPath);
+ }*/
+ }
+
+ private void addViewFacelets(List<String> viewPaths, String pathBase)
+ {
+ Set<String> paths = externalContext.getResourcePaths(pathBase);
+ for (String path : paths)
+ {
+ if (path.endsWith(".xhtml"))
+ {
+ viewPaths.add(path);
+ }
+ else if (path.endsWith("/"))
+ {
+ addViewFacelets(viewPaths, path);
+ }
+ }
+ }
+
+
+ @Override
+ protected String getDirectory()
+ {
+ return "webapp";
+ }
+
+}
diff --git a/client-window-example/src/test/resources/webapp/README.txt b/client-window-example/src/test/resources/webapp/README.txt
new file mode 100644
index 0000000..13e8319
--- /dev/null
+++ b/client-window-example/src/test/resources/webapp/README.txt
@@ -0,0 +1 @@
+This folder is just a hard copy of the files on src/main/webapp, to make them available on testing time using junit. Please do not edit anything here or you will lose the changes.
\ No newline at end of file
diff --git a/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java b/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
index 977fabc..0899bbd 100755
--- a/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImpl.java
@@ -38,6 +38,8 @@ import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.faces.context.PartialResponseWriter;
import javax.faces.context.PartialViewContext;
+import javax.faces.lifecycle.ClientWindow;
+import javax.faces.render.ResponseStateManager;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@@ -314,13 +316,36 @@ public final class ServletExternalContextImpl extends ServletExternalContextImpl
{
checkNull(url, "url");
checkHttpServletRequest();
- return ((HttpServletResponse) _servletResponse).encodeURL(url);
+ String encodedUrl = ((HttpServletResponse) _servletResponse).encodeURL(url);
+ encodedUrl = encodeWindowId(encodedUrl);
+ return encodedUrl;
+ }
+
+ private String encodeWindowId(String encodedUrl)
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ if (ClientWindow.isClientWindowUrlQueryParameterEnabled(facesContext))
+ {
+ //TODO: Use StringBuilder or some optimization.
+ ClientWindow window = facesContext.getExternalContext().getClientWindow();
+ if (window != null)
+ {
+ if (!encodedUrl.contains(ResponseStateManager.CLIENT_WINDOW_URL_PARAM))
+ {
+ encodedUrl = encodedUrl + ( (encodedUrl.indexOf(URL_QUERY_SEPERATOR) != -1) ?
+ URL_PARAM_SEPERATOR : URL_QUERY_SEPERATOR ) +
+ ResponseStateManager.CLIENT_WINDOW_URL_PARAM +
+ URL_NAME_VALUE_PAIR_SEPERATOR+ window.getId();
+ }
+ }
+ }
+ return encodedUrl;
}
@Override
public String encodeBookmarkableURL(String baseUrl, Map<String,List<String>> parameters)
{
- return encodeURL(baseUrl, parameters);
+ return encodeWindowId(encodeURL(baseUrl, parameters));
}
@Override
@@ -342,13 +367,13 @@ public final class ServletExternalContextImpl extends ServletExternalContextImpl
{
checkNull(url, "url");
checkHttpServletRequest();
- return ((HttpServletResponse) _servletResponse).encodeURL(url);
+ return encodeWindowId(((HttpServletResponse) _servletResponse).encodeURL(url));
}
@Override
public String encodeRedirectURL(String baseUrl, Map<String,List<String>> parameters)
{
- return _httpServletResponse.encodeRedirectURL(encodeURL(baseUrl, parameters));
+ return encodeWindowId(_httpServletResponse.encodeRedirectURL(encodeURL(baseUrl, parameters)));
}
@Override
diff --git a/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImplBase.java b/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImplBase.java
index e5c4446..672da03 100644
--- a/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImplBase.java
+++ b/impl/src/main/java/org/apache/myfaces/context/servlet/ServletExternalContextImplBase.java
@@ -25,6 +25,7 @@ import java.util.Map;
import java.util.Set;
import javax.faces.context.ExternalContext;
+import javax.faces.lifecycle.ClientWindow;
import javax.servlet.ServletContext;
import org.apache.myfaces.context.ReleaseableExternalContext;
@@ -46,12 +47,15 @@ public abstract class ServletExternalContextImplBase extends ExternalContext
private ServletContext _servletContext;
private Map<String, Object> _applicationMap;
private Map<String, String> _initParameterMap;
+ private ClientWindow _clientWindow;
+
public ServletExternalContextImplBase(ServletContext servletContext)
{
_servletContext = servletContext;
_applicationMap = null;
_initParameterMap = null;
+ _clientWindow = null;
}
public void release()
@@ -59,6 +63,7 @@ public abstract class ServletExternalContextImplBase extends ExternalContext
_servletContext = null;
_applicationMap = null;
_initParameterMap = null;
+ _clientWindow = null;
}
// ~ Methods which only rely on the ServletContext-------------------------
@@ -159,6 +164,16 @@ public abstract class ServletExternalContextImplBase extends ExternalContext
return _servletContext.getRealPath(path);
}
+ public ClientWindow getClientWindow()
+ {
+ return _clientWindow;
+ }
+
+ public void setClientWindow(ClientWindow window)
+ {
+ _clientWindow = window;
+ }
+
// ~ Methods which verify some required behavior---------------------------
protected void checkNull(final Object o, final String param)
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/CODIClientSideWindow.java b/impl/src/main/java/org/apache/myfaces/lifecycle/CODIClientSideWindow.java
new file mode 100644
index 0000000..fd182b2
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/CODIClientSideWindow.java
@@ -0,0 +1,424 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.lifecycle;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import javax.faces.FacesException;
+import javax.faces.application.Resource;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.lifecycle.ClientWindow;
+import javax.faces.render.ResponseStateManager;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ * @author lu4242
+ */
+public class CODIClientSideWindow extends ClientWindow
+{
+ /**
+ * Key for storing the window-id e.g. in URLs
+ */
+ //private static final String WINDOW_CONTEXT_ID_PARAMETER_KEY =
+ // ResponseStateManager.CLIENT_WINDOW_URL_PARAM;
+
+ /**
+ * Value which can be used as "window-id" by external clients which aren't aware of windows.
+ * It deactivates e.g. the redirect for the initial request.
+ */
+ private static final String AUTOMATED_ENTRY_POINT_PARAMETER_KEY = "automatedEntryPoint";
+
+ private static final long serialVersionUID = 5293942986187078113L;
+
+ private static final String WINDOW_ID_COOKIE_PREFIX = "jfwid-";
+ private static final String CODI_REQUEST_TOKEN = "mfRid";
+
+ 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$$";
+ private static final String NOSCRIPT_PARAMETER = "mfDirect";
+
+ private final ClientConfig clientConfig;
+
+ private final WindowContextConfig windowContextConfig;
+
+ private final TokenGenerator clientWindowTokenGenerator;
+
+ private String windowId;
+
+ private String unparsedWindowHandlerHtml = null;
+
+ /*
+ protected CODIClientSideWindow()
+ {
+ // needed for proxying
+ }*/
+
+ protected CODIClientSideWindow(TokenGenerator clientWindowTokenGenerator,
+ WindowContextConfig windowContextConfig,
+ ClientConfig clientConfig)
+ {
+ this.windowContextConfig = windowContextConfig;
+ this.clientConfig = clientConfig;
+ this.clientWindowTokenGenerator = clientWindowTokenGenerator;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ /*
+ public String restoreWindowId(ExternalContext externalContext)
+ {
+ if (this.clientConfig.isJavaScriptEnabled())
+ {
+ return (String) externalContext.getRequestMap().get(
+ WINDOW_CONTEXT_ID_PARAMETER_KEY);
+ }
+ else
+ {
+ // fallback
+ //if(!this.useWindowAwareUrlEncoding)
+ //{
+ // return null;
+ //}
+
+ return externalContext.getRequestParameterMap().get(WINDOW_CONTEXT_ID_PARAMETER_KEY);
+ }
+ }*/
+
+ /**
+ * {@inheritDoc}
+ */
+ //public void beforeLifecycleExecute(FacesContext facesContext)
+ public void decode(FacesContext facesContext)
+ {
+ if (facesContext.isPostback())
+ {
+ // In postback, we can safely ignore the query param, because it is not useful
+ if (getId() == null)
+ {
+ setId(calculateWindowIdFromPost(facesContext));
+ }
+ }
+
+ if (!isClientSideWindowHandlerRequest(facesContext))
+ {
+ return;
+ }
+
+ ExternalContext externalContext = facesContext.getExternalContext();
+
+ if (isNoscriptRequest(externalContext))
+ {
+ // the client has JavaScript disabled
+ clientConfig.setJavaScriptEnabled(false);
+ return;
+ }
+
+ String windowId = getWindowIdFromCookie(externalContext);
+ if (windowId == null)
+ {
+ // GET request without windowId - send windowhandlerfilter.html to get the windowId
+ sendWindowHandlerHtml(facesContext, null);
+ facesContext.responseComplete();
+ }
+ else
+ {
+ if (AUTOMATED_ENTRY_POINT_PARAMETER_KEY.equals(windowId) ||
+ (!windowContextConfig.isUnknownWindowIdsAllowed() /*&&
+ !ConversationUtils.isWindowActive(this.windowContextManager, windowId)*/))
+ {
+ // no or invalid windowId --> create new one
+ // don't use createWindowId() the following call will ensure the max. window context count,...
+ //windowId = this.windowContextManager.getCurrentWindowContext().getId();
+ windowId = createWindowId(facesContext);
+
+ // GET request with NEW windowId - send windowhandlerfilter.html to set and re-get the windowId
+ sendWindowHandlerHtml(facesContext, windowId);
+ facesContext.responseComplete();
+ }
+ else
+ {
+ // we have a valid windowId - set it and continue with the request
+ // TODO only set internally and provide via restoreWindowId()?
+ //externalContext.getRequestMap().put(WINDOW_CONTEXT_ID_PARAMETER_KEY, windowId);
+ setId(windowId);
+ }
+ }
+ }
+
+ public String calculateWindowIdFromPost(FacesContext context)
+ {
+ //1. If it comes as parameter, it takes precedence over any other choice, because
+ // no browser is capable to do a POST and create a new window at the same time.
+ String windowId = context.getExternalContext().getRequestParameterMap().get(
+ ResponseStateManager.CLIENT_WINDOW_PARAM);
+ if (windowId != null)
+ {
+ return windowId;
+ }
+ return null;
+ }
+
+ private boolean isClientSideWindowHandlerRequest(FacesContext facesContext)
+ {
+ // no POST request and javascript enabled
+ // NOTE that for POST-requests the windowId is saved in the state (see WindowContextIdHolderComponent)
+ return !facesContext.isPostback() && clientConfig.isClientSideWindowHandlerRequest(facesContext);
+ }
+
+ private boolean isNoscriptRequest(ExternalContext externalContext)
+ {
+ String noscript = externalContext.getRequestParameterMap().get(NOSCRIPT_PARAMETER);
+
+ return (noscript != null && "true".equals(noscript));
+ }
+
+ private void sendWindowHandlerHtml(FacesContext facesContext, String windowId)
+ {
+ HttpServletResponse httpResponse = (HttpServletResponse) facesContext.getExternalContext().getResponse();
+
+ try
+ {
+ httpResponse.setStatus(HttpServletResponse.SC_OK);
+ httpResponse.setContentType("text/html");
+
+ if (unparsedWindowHandlerHtml == null)
+ {
+ Resource resource = facesContext.getApplication().getResourceHandler().createResource(
+ "windowhandler.html", "org.apache.myfaces.windowId");
+
+ unparsedWindowHandlerHtml = convertStreamToString(resource.getInputStream());
+ }
+
+ String windowHandlerHtml = unparsedWindowHandlerHtml;
+
+ 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(facesContext.getExternalContext()));
+
+ OutputStream os = httpResponse.getOutputStream();
+ try
+ {
+ os.write(windowHandlerHtml.getBytes());
+ }
+ finally
+ {
+ os.close();
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new FacesException(ioe);
+ }
+ }
+
+ private static String convertStreamToString(InputStream is)
+ {
+ StringBuilder sb = new StringBuilder();
+ try
+ {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ String line = null;
+ while ((line = reader.readLine()) != null)
+ {
+ sb.append(line + "\n");
+ }
+ }
+ catch (IOException e)
+ {
+ throw new FacesException(e);
+ }
+ finally
+ {
+ if (is != null)
+ {
+ try
+ {
+ is.close();
+ }
+ catch (IOException e)
+ {
+ //No op
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ 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 = addParameters(externalContext, url, true, true, 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;
+ }
+
+ /**
+ * Adds the current request-parameters to the given url
+ * @param externalContext current external-context
+ * @param url current url
+ * @param addRequestParameter flag which indicates if the request params should be added or not
+ * @param addPageParameter flag which indicates if the view params should be added or not {@see ViewParameter}
+ * @param encodeValues flag which indicates if parameter values should be encoded or not
+ * @return url with request-parameters
+ */
+ public static String addParameters(ExternalContext externalContext, String url,
+ boolean addRequestParameter, boolean addPageParameter, boolean encodeValues)
+ {
+ StringBuilder finalUrl = new StringBuilder(url);
+ boolean existingParameters = url.contains("?");
+ boolean urlContainsWindowId = url.contains(ResponseStateManager.CLIENT_WINDOW_URL_PARAM + "=");
+
+ /* TODO: implement me
+ for(RequestParameter requestParam :
+ getParameters(externalContext, true, addRequestParameter, addPageParameter))
+ {
+ String key = requestParam.getKey();
+
+ //TODO eval if we should also filter the other params
+ if(WindowContextManager.WINDOW_CONTEXT_ID_PARAMETER_KEY.equals(key) && urlContainsWindowId)
+ {
+ continue;
+ }
+
+ for(String parameterValue : requestParam.getValues())
+ {
+ if(!url.contains(key + "=" + parameterValue) &&
+ !url.contains(key + "=" + encodeURLParameterValue(parameterValue, externalContext)))
+ {
+ if(!existingParameters)
+ {
+ finalUrl.append("?");
+ existingParameters = true;
+ }
+ else
+ {
+ finalUrl.append("&");
+ }
+ finalUrl.append(key);
+ finalUrl.append("=");
+
+ if(encodeValues)
+ {
+ finalUrl.append(encodeURLParameterValue(parameterValue, externalContext));
+ }
+ else
+ {
+ finalUrl.append(parameterValue);
+ }
+ }
+ }
+ }
+ */
+ return finalUrl.toString();
+ }
+
+ protected String createWindowId(FacesContext context)
+ {
+ String windowId = clientWindowTokenGenerator._getNextToken();
+ setId(windowId);
+ return windowId;
+ }
+
+ private String getWindowIdFromCookie(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(CODI_REQUEST_TOKEN);
+ if (requestToken != null)
+ {
+ return requestToken;
+ }
+
+ return "";
+ }
+
+ @Override
+ public String getId()
+ {
+ return windowId;
+ }
+
+ public void setId(String id)
+ {
+ windowId = id;
+ }
+
+}
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/ClientConfig.java b/impl/src/main/java/org/apache/myfaces/lifecycle/ClientConfig.java
new file mode 100644
index 0000000..e9d491f
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/ClientConfig.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.lifecycle;
+
+
+import javax.faces.context.FacesContext;
+import java.io.Serializable;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+
+/**
+ * Contains information about whether the user has
+ * JavaScript enabled on his client, etc.
+ * It also contains the windowhandler html which gets sent to
+ * the browser to detect the current windowId.
+ *
+ * This allows the 'customisation' of this html file to e.g.
+ * adopt the background colour to avoid screen flickering.
+ *
+ * Please note that all subclasses of ClientConfig should also
+ * be @SessionScoped as well!
+ */
+public class ClientConfig implements Serializable
+{
+ private static final long serialVersionUID = 581351549574404793L;
+
+ /** 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 = "mfNoScriptEnabled";
+
+ private volatile Boolean javaScriptEnabled = null;
+
+ protected String windowHandlerHtml;
+
+ /** lazily initiated via {@link #getUserAgent(javax.faces.context.FacesContext)} */
+ private volatile String userAgent = null;
+
+ /**
+ * The location of the default windowhandler resource
+ */
+ //private static final String DEFAULT_WINDOW_HANDLER_HTML_FILE = "static/windowhandler.html";
+
+ /**
+ * Defaults to <code>true</code>.
+ * @return if the user has JavaScript enabled
+ */
+ 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((String) cookie.getValue());
+ }
+ }
+ }
+ }
+ }
+ return javaScriptEnabled;
+ }
+
+ /**
+ * Set it to <code>false</code> if you don't like to use the
+ * JavaScript based client side windowhandler. In this case
+ * the request will be returned directly.
+ * @param javaScriptEnabled
+ */
+ public void setJavaScriptEnabled(boolean javaScriptEnabled)
+ {
+ this.javaScriptEnabled = javaScriptEnabled;
+
+ // and now also store this information inside a cookie!
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ if (facesContext != null)
+ {
+ Object r = facesContext.getExternalContext().getResponse();
+ if (r instanceof HttpServletResponse)
+ {
+ Cookie cookie = new Cookie(COOKIE_NAME_NOSCRIPT_ENABLED, "" + javaScriptEnabled);
+ cookie.setPath("/"); // for all the server
+ HttpServletResponse response = (HttpServletResponse) r;
+ response.addCookie(cookie);
+ }
+ }
+ }
+
+ /**
+ * For branding the whole windowhandler page - e.g. not only change the
+ * background color, add some images and empty menu structure
+ * or the language of the message text - you can just copy the content of the
+ * {@link #DEFAULT_WINDOW_HANDLER_HTML_FILE} and adopt it to your needs.
+ *
+ * The reason for this is to minimize visual side effects on browsers who do
+ * not properly support html5 localstorage.
+ *
+ * @return the location of the <i>windowhandler.html</i> resource
+ * which should be sent to the users browser.
+ */
+ /*
+ public String getWindowHandlerResourceLocation()
+ {
+ return DEFAULT_WINDOW_HANDLER_HTML_FILE;
+ }*/
+
+ /**
+ * This might return different windowhandlers based on user settings like
+ * his language, an affiliation, etc
+ * @return a String containing the whole windowhandler.html file.
+ * @throws IOException
+ */
+ /*
+ public String getWindowHandlerHtml() throws IOException
+ {
+ if (FacesContext.getCurrentInstance().isProjectStage(ProjectStage.Development)
+ && windowHandlerHtml != null)
+ {
+ // use cached windowHandlerHtml except in Development
+ return windowHandlerHtml;
+ }
+
+ InputStream is = ClassUtils.getContextClassLoader().getResourceAsStream(
+ getWindowHandlerResourceLocation());
+ 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);
+ }
+ }
+ finally
+ {
+ is.close();
+ }
+
+ windowHandlerHtml = sb.toString();
+
+ return windowHandlerHtml;
+ }*/
+
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Users can overload this method to define in which scenarios a request should result
+ * in an 'intercepted' page with proper windowId detection. This can e.g. contain
+ * blacklisting some userAgents.
+ * By default the following User-Agents will be served directly:
+ * <ul>
+ * <li>.*bot.*</li>
+ * <li>.*Bot.*</li>
+ * <li>.*Slurp.*</li>
+ * <li>.*Crawler.*</li>
+ * </ul>
+ * @return <code>true</code> if the Request should get 'intercepted' and the intermediate
+ * windowhandler.html page should get rendered first. By returning <code>false</code>
+ * the requested page will get rendered intermediately.
+ * @see #getUserAgent(javax.faces.context.FacesContext) for determining the UserAgent
+ */
+ public boolean isClientSideWindowHandlerRequest(FacesContext facesContext)
+ {
+ if (!isJavaScriptEnabled())
+ {
+ return false;
+ }
+
+ 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 false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java b/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java
index c4289bd..80a63e9 100755
--- a/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/LifecycleImpl.java
@@ -31,9 +31,11 @@ import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
+import javax.faces.lifecycle.ClientWindow;
import javax.faces.lifecycle.Lifecycle;
import org.apache.myfaces.config.FacesConfigurator;
+import org.apache.myfaces.shared.util.WebConfigParamUtils;
import org.apache.myfaces.shared_impl.webapp.webxml.WebXml;
import org.apache.myfaces.util.DebugUtils;
@@ -88,6 +90,15 @@ public class LifecycleImpl extends Lifecycle
* Replaced by _phaseListenerList CopyOnWriteArrayList
*/
//private PhaseListener[] _phaseListenerArray = null;
+
+ private String windowMode;
+ private TokenGenerator windowTokenGenerator;
+ private ClientConfig clientConfig;
+ private WindowContextConfig windowContextConfig;
+
+ private static final String WINDOW_MODE_NONE = "none";
+ private static final String WINDOW_MODE_URL = "url";
+ private static final String WINDOW_MODE_CLIENT = "client";
public LifecycleImpl()
{
@@ -96,6 +107,49 @@ public class LifecycleImpl extends Lifecycle
new ProcessValidationsExecutor(), new UpdateModelValuesExecutor(), new InvokeApplicationExecutor() };
renderExecutor = new RenderResponseExecutor();
+ windowTokenGenerator = new TokenGenerator();
+ clientConfig = new ClientConfig();
+ windowContextConfig = new WindowContextConfig();
+ }
+
+ private String getWindowMode(FacesContext context)
+ {
+ if (windowMode == null)
+ {
+ windowMode = WebConfigParamUtils.getStringInitParameter(
+ context.getExternalContext(),
+ ClientWindow.CLIENT_WINDOW_MODE_PARAM_NAME, WINDOW_MODE_NONE);
+ }
+ return windowMode;
+ }
+
+ @Override
+ public void attachWindow(FacesContext facesContext)
+ {
+ if (WINDOW_MODE_NONE.equals(getWindowMode(facesContext)))
+ {
+ //No need to do anything
+ return;
+ }
+ else
+ {
+ ClientWindow clientWindow = facesContext.getExternalContext().getClientWindow();
+ if (clientWindow == null)
+ {
+ if (WINDOW_MODE_URL.equals(getWindowMode(facesContext)))
+ {
+ clientWindow = new UrlClientWindow(windowTokenGenerator);
+ }
+ else
+ {
+ //clientWindow = new DefaultClientWindow(windowTokenGenerator);
+ clientWindow = new CODIClientSideWindow(windowTokenGenerator,
+ windowContextConfig, clientConfig);
+ }
+ clientWindow.decode(facesContext);
+ facesContext.getExternalContext().setClientWindow(clientWindow);
+ }
+ }
}
@Override
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/TokenGenerator.java b/impl/src/main/java/org/apache/myfaces/lifecycle/TokenGenerator.java
new file mode 100644
index 0000000..8e30cd1
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/TokenGenerator.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.lifecycle;
+
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ *
+ * @author lu4242
+ */
+class TokenGenerator
+{
+ private final AtomicLong _count;
+
+ public TokenGenerator()
+ {
+ _count = new AtomicLong(_getSeed());
+ }
+
+ private static long _getSeed()
+ {
+ SecureRandom rng;
+ try
+ {
+ // try SHA1 first
+ rng = SecureRandom.getInstance("SHA1PRNG");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // SHA1 not present, so try the default (which could potentially not be
+ // cryptographically secure)
+ rng = new SecureRandom();
+ }
+
+ // use 48 bits for strength and fill them in
+ byte[] randomBytes = new byte[6];
+ rng.nextBytes(randomBytes);
+
+ // convert to a long
+ return new BigInteger(randomBytes).longValue();
+ }
+
+ /**
+ * Get the next token to be assigned to this request
+ *
+ * @return
+ */
+ String _getNextToken()
+ {
+ // atomically increment the value
+ long nextToken = _count.incrementAndGet();
+
+ // convert using base 36 because it is a fast efficient subset of base-64
+ return Long.toString(nextToken, 36);
+ }
+}
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/UrlClientWindow.java b/impl/src/main/java/org/apache/myfaces/lifecycle/UrlClientWindow.java
new file mode 100644
index 0000000..1d4984e
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/UrlClientWindow.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.lifecycle;
+
+import javax.faces.context.FacesContext;
+import javax.faces.lifecycle.ClientWindow;
+import javax.faces.render.ResponseStateManager;
+
+/**
+ *
+ * @author lu4242
+ */
+public class UrlClientWindow extends ClientWindow
+{
+ private String windowId;
+
+ private TokenGenerator tokenGenerator;
+
+ public UrlClientWindow(TokenGenerator tokenGenerator)
+ {
+ this.tokenGenerator = tokenGenerator;
+ }
+
+ @Override
+ public void decode(FacesContext context)
+ {
+ String windowId = calculateWindowId(context);
+
+ if (windowId != null)
+ {
+ // Store the current windowId.
+ setId(windowId);
+ }
+ else
+ {
+ //Generate a new windowId
+ setId(tokenGenerator._getNextToken());
+ }
+ }
+
+ protected String calculateWindowId(FacesContext context)
+ {
+ //1. If it comes as parameter, it takes precedence over any other choice, because
+ // no browser is capable to do a POST and create a new window at the same time.
+ String windowId = context.getExternalContext().getRequestParameterMap().get(
+ ResponseStateManager.CLIENT_WINDOW_PARAM);
+ if (windowId != null)
+ {
+ return windowId;
+ }
+ windowId = context.getExternalContext().getRequestParameterMap().get(
+ ResponseStateManager.CLIENT_WINDOW_URL_PARAM);
+ if (windowId != null)
+ {
+ return windowId;
+ }
+ return null;
+ }
+
+ @Override
+ public String getId()
+ {
+ return windowId;
+ }
+
+ public void setId(String id)
+ {
+ windowId = id;
+ }
+
+}
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/WindowContextConfig.java b/impl/src/main/java/org/apache/myfaces/lifecycle/WindowContextConfig.java
new file mode 100644
index 0000000..211c1a0
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/WindowContextConfig.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.lifecycle;
+
+/**
+ * Configuration for the {@link org.apache.myfaces.extensions.cdi.core.api.scope.conversation.WindowContext}
+ * - it's customizable via the @Alternative or @Specializes mechanism of CDI.
+ */
+public class WindowContextConfig
+{
+ private static final long serialVersionUID = 8159770064249255686L;
+
+ protected WindowContextConfig()
+ {
+ }
+
+ /**
+ * Specifies if it is allowed to use URL params for forwarding the current window-id.
+ * (deactivate it e.g. for higher security - in this case it's required to use a window id provided by a
+ * component lib or a server-side window-handler)
+ *
+ * @return true if it is allowed to add the window-id as URL parameter
+ */
+ public boolean isUrlParameterSupported()
+ {
+ return true;
+ }
+
+ /**
+ * Allows to restrict window-ids.
+ * <p>With the default window handler (esp. for JSF 1.2), URLs have to contain the window-id.
+ * If users bookmark these links, they could open 2-n tabs (with the bookmark) which have the same window-id.
+ * It is only possible to prevent it if the ClientSideWindowHandler is used.
+ * </p>
+ *
+ * <p><b>ATTENTION:</b> Since CODI-1.0.6 this is set to <code>true</code> as defalt!</p>
+ *
+ * <p>
+ * This must be enabled to
+ * <ul>
+ * <li>allow <i>target</i> attributes in a href</li>
+ * <li>support multiple webapps in an EAR scenario. Since each webapp has it's own session,
+ * they would otherwise trash their windowIds each time you link from one webapp to another one</li>
+ * <li>play nicely with other frameworks which use the window.name for browser tab detection</li>
+ * </ul>
+ * </p>
+ * @return <code>true</code> to allow all windowIds already present in window.name.
+ * <code>false</code> to only allow window-ids which are generated by CODI
+ */
+ public boolean isUnknownWindowIdsAllowed()
+ {
+ return true;
+ }
+
+ /**
+ * if set to <code>true</code> CODI will add a windowId=xxx parameter
+ * while encoding each action URL.
+ * @return true if the window-id should be added, false otherwise
+ */
+ public boolean isAddWindowIdToActionUrlsEnabled()
+ {
+ return false;
+ }
+
+ /**
+ * Specifies the time for the timeout for a window. After a timeout is detected all beans which are only linked
+ * to the window will be destroyed.
+ *
+ * @return the time for the timeout for a window
+ */
+ public int getWindowContextTimeoutInMinutes()
+ {
+ return 60;
+ }
+
+ /**
+ * Restricts the number of active windows.
+ *
+ * @return limit for active windows
+ */
+ public int getMaxWindowContextCount()
+ {
+ return 64;
+ }
+
+ /**
+ * Allows to activate the cleanup of empty window contexts to avoid cleanup e.g.
+ * of the eldest window context instances if the max. count is reached.
+ *
+ * @return true for activating it, false otherwise
+ */
+ public boolean isCloseEmptyWindowContextsEnabled()
+ {
+ return false;
+ }
+
+ /**
+ * Allows to restore the window-context before the component tree gets built.
+ *
+ * @return true for activating it, false otherwise
+ */
+ public boolean isEagerWindowContextDetectionEnabled()
+ {
+ return true;
+ }
+
+ /*
+ * event config
+ */
+
+ /**
+ * Specifies if the
+ * {@link org.apache.myfaces.extensions.cdi.core.api.scope.conversation.event.CreateWindowContextEvent}
+ * will be fired.
+ *
+ * @return true if the event should be fired, false otherwise
+ */
+ public boolean isCreateWindowContextEventEnabled()
+ {
+ return false;
+ }
+
+ /**
+ * Specifies if the
+ * {@link org.apache.myfaces.extensions.cdi.core.api.scope.conversation.event.CloseWindowContextEvent}
+ * will be fired.
+ *
+ * @return true if the event should be fired, false otherwise
+ */
+ public boolean isCloseWindowContextEventEnabled()
+ {
+ return false;
+ }
+
+ //boolean isResetWindowContextEventEnable();
+}
diff --git a/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java b/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
index 5d5593d..e07e7fa 100644
--- a/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
+++ b/impl/src/main/java/org/apache/myfaces/renderkit/ServerSideStateCacheImpl.java
@@ -43,10 +43,12 @@ import javax.faces.application.ProjectStage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
+import javax.faces.lifecycle.ClientWindow;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.collections.map.AbstractReferenceMap;
+import org.apache.commons.collections.map.LRUMap;
import org.apache.commons.collections.map.ReferenceMap;
import org.apache.myfaces.application.StateCache;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
@@ -305,7 +307,16 @@ class ServerSideStateCacheImpl extends StateCache<Object, Object>
if (key == null )
{
- if (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) &&
+ // Check if clientWindow is enabled and if the last view key is stored
+ // into session, so we can use it to chain the precedence in GET-GET
+ // cases.
+ ClientWindow clientWindow = context.getExternalContext().getClientWindow();
+ if (clientWindow != null)
+ {
+ key = (SerializedViewKey) viewCollection.
+ getLastWindowKey(context, clientWindow.getId());
+ }
+ else if (isUseFlashScopePurgeViewsInSession(context.getExternalContext()) &&
Boolean.TRUE.equals(context.getExternalContext().getRequestMap()
.get("oam.Flash.REDIRECT.PREVIOUSREQUEST")))
{
@@ -319,6 +330,13 @@ class ServerSideStateCacheImpl extends StateCache<Object, Object>
context, context.getViewRoot().getViewId(), getNextViewSequence(context));
viewCollection.add(context, serializeView(context, serializedView), nextKey, key);
+ ClientWindow clientWindow = context.getExternalContext().getClientWindow();
+ if (clientWindow != null)
+ {
+ //Update the last key generated for the current windowId in session map
+ viewCollection.putLastWindowKey(context, clientWindow.getId(), nextKey);
+ }
+
// replace the value to notify the container about the change
sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
}
@@ -599,6 +617,8 @@ class ServerSideStateCacheImpl extends StateCache<Object, Object>
private final Map<SerializedViewKey, SerializedViewKey> _precedence =
new HashMap<SerializedViewKey, SerializedViewKey>();
+
+ private Map<String, SerializedViewKey> _lastWindowKeys = null;
// old views will be hold as soft references which will be removed by
// the garbage collector if free memory is low
@@ -744,6 +764,29 @@ class ServerSideStateCacheImpl extends StateCache<Object, Object>
}
return views;
}
+
+ public synchronized void putLastWindowKey(FacesContext context, String id, SerializedViewKey key)
+ {
+ if (_lastWindowKeys == null)
+ {
+ Integer i = getNumberOfSequentialViewsInSession(context);
+ int j = getNumberOfViewsInSession(context);
+ if (i != null && i.intValue() > 0)
+ {
+ _lastWindowKeys = new LRUMap((j / i.intValue()) + 1);
+ }
+ }
+ _lastWindowKeys.put(id, key);
+ }
+
+ public SerializedViewKey getLastWindowKey(FacesContext context, String id)
+ {
+ if (_lastWindowKeys != null)
+ {
+ return _lastWindowKeys.get(id);
+ }
+ return null;
+ }
/**
* @return old serialized views map
diff --git a/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java b/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java
index ad941da..845aa95 100755
--- a/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java
+++ b/impl/src/main/java/org/apache/myfaces/renderkit/html/HtmlResponseStateManager.java
@@ -19,12 +19,15 @@
package org.apache.myfaces.renderkit.html;
import java.io.IOException;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.faces.component.UINamingContainer;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
+import javax.faces.lifecycle.ClientWindow;
import javax.faces.render.RenderKitFactory;
import javax.faces.render.ResponseStateManager;
@@ -73,6 +76,8 @@ public class HtmlResponseStateManager extends MyfacesResponseStateManager
private StateCacheFactory _stateCacheFactory;
+ private AtomicLong _counter = new AtomicLong();
+
public HtmlResponseStateManager()
{
_stateCacheFactory = new StateCacheFactoryImpl();
@@ -139,6 +144,32 @@ public class HtmlResponseStateManager extends MyfacesResponseStateManager
// renderKitId field
writeRenderKitIdField(facesContext, responseWriter);
+
+ // windowId field
+ writeWindowIdField(facesContext, responseWriter);
+ }
+
+ private void writeWindowIdField(FacesContext facesContext, ResponseWriter responseWriter) throws IOException
+ {
+ ClientWindow clientWindow = facesContext.getExternalContext().getClientWindow();
+ if (clientWindow != null)
+ {
+ responseWriter.startElement(HTML.INPUT_ELEM, null);
+ responseWriter.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, null);
+ StringBuilder sb = new StringBuilder();
+ char sepChar = UINamingContainer.getSeparatorChar(facesContext);
+ sb.append(facesContext.getViewRoot().getContainerClientId(facesContext));
+ sb.append(sepChar);
+ sb.append(ResponseStateManager.CLIENT_WINDOW_PARAM);
+ sb.append(sepChar);
+ // A counter is enough, because only uniqueness of UIViewRoot
+ // per page is needed
+ sb.append(_counter.incrementAndGet());
+ responseWriter.writeAttribute(HTML.ID_ATTR, sb.toString(), null);
+ responseWriter.writeAttribute(HTML.NAME_ATTR, ResponseStateManager.CLIENT_WINDOW_PARAM, null);
+ responseWriter.writeAttribute(HTML.VALUE_ATTR, clientWindow.getId(), null);
+ responseWriter.endElement(HTML.INPUT_ELEM);
+ }
}
@Override
diff --git a/impl/src/main/java/org/apache/myfaces/view/facelets/util/Classpath.java b/impl/src/main/java/org/apache/myfaces/view/facelets/util/Classpath.java
index 895b047..b2f5ee4 100644
--- a/impl/src/main/java/org/apache/myfaces/view/facelets/util/Classpath.java
+++ b/impl/src/main/java/org/apache/myfaces/view/facelets/util/Classpath.java
@@ -38,6 +38,8 @@ import java.util.zip.ZipInputStream;
import org.apache.myfaces.shared.util.ClassUtils;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
/**
* @author Jacob Hookom
* @author Roland Huss
@@ -120,7 +122,23 @@ public final class Classpath
private static boolean _searchDir(Set<URL> result, File dir, String suffix) throws IOException
{
- if (dir.exists() && dir.isDirectory())
+ boolean dirExists = false;
+ if (System.getSecurityManager() != null)
+ {
+ final File finalDir = dir;
+ dirExists = (Boolean) AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ return finalDir.exists();
+ }
+ });
+ }
+ else
+ {
+ dirExists = dir.exists();
+ }
+ if (dirExists && dir.isDirectory())
{
for (File file : dir.listFiles())
{
diff --git a/impl/src/main/resources/META-INF/resources/org.apache.myfaces.windowId/windowhandler.html b/impl/src/main/resources/META-INF/resources/org.apache.myfaces.windowId/windowhandler.html
new file mode 100644
index 0000000..6469f29
--- /dev/null
+++ b/impl/src/main/resources/META-INF/resources/org.apache.myfaces.windowId/windowhandler.html
@@ -0,0 +1,215 @@
+<!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>
+<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;
+}
+
+function scrollToOldPosition() {
+ if (isHtml5()) {
+ var x = localStorage.getItem(window.name + '_x');
+ var y = localStorage.getItem(window.name + '_y');
+ window.scrollTo(x, y);
+
+ var x = localStorage.removeItem(window.name + '_x');
+ var y = localStorage.removeItem(window.name + '_y');
+ }
+}
+
+replaceContent();
+
+
+window.onload = function() {
+
+ loadCss(true);
+ //X scrollToOldPosition();
+
+ // this will be replaced in the phase listener
+ var windowId = '$$windowIdValue$$';
+
+ if (windowId == 'uninitializedWindowId')
+ {
+ windowId = window.name
+ }
+
+ if (!windowId || windowId.length < 3)
+ {
+ // request a new windowId
+ windowId = 'automatedEntryPoint';
+ }
+
+ window.name = windowId;
+
+ /* used 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, "mfRid", requestToken);
+ newUrl = setUrlParam(newUrl, "jfwid", windowId);
+
+ document.cookie = 'jfwid-' + requestToken + '=' + windowId + expires+"; path=/";
+
+ window.location = newUrl;
+}
+</script>
+
+</html>
+
diff --git a/pom.xml b/pom.xml
index e265007..14cb177 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,6 +56,7 @@
<module>shared</module>
<module>impl</module>
<module>bundle</module>
+ <module>client-window-example</module>
</modules>
<build>
diff --git a/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java b/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java
index 2993230..00701d1 100644
--- a/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/context/flash/FlashImpl.java
@@ -40,6 +40,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;
+import javax.faces.lifecycle.ClientWindow;
/**
* Implementation of Flash object
@@ -731,18 +732,27 @@ public class FlashImpl extends Flash
private void _saveRenderFlashMapTokenForNextRequest(ExternalContext externalContext)
{
String tokenValue = (String) externalContext.getRequestMap().get(FLASH_RENDER_MAP_TOKEN);
-
- HttpServletResponse httpResponse = ExternalContextUtils.getHttpServletResponse(externalContext);
- if (httpResponse != null)
+ ClientWindow clientWindow = externalContext.getClientWindow();
+ if (clientWindow != null)
{
- Cookie cookie = _createFlashCookie(FLASH_RENDER_MAP_TOKEN, tokenValue, externalContext);
- httpResponse.addCookie(cookie);
+ //Use HttpSession or PortletSession object
+ Map<String, Object> sessionMap = externalContext.getSessionMap();
+ sessionMap.put(FLASH_RENDER_MAP_TOKEN+SEPARATOR_CHAR+clientWindow.getId(), tokenValue);
}
else
{
- //Use HttpSession or PortletSession object
- Map<String, Object> sessionMap = externalContext.getSessionMap();
- sessionMap.put(FLASH_RENDER_MAP_TOKEN, tokenValue);
+ HttpServletResponse httpResponse = ExternalContextUtils.getHttpServletResponse(externalContext);
+ if (httpResponse != null)
+ {
+ Cookie cookie = _createFlashCookie(FLASH_RENDER_MAP_TOKEN, tokenValue, externalContext);
+ httpResponse.addCookie(cookie);
+ }
+ else
+ {
+ //Use HttpSession or PortletSession object
+ Map<String, Object> sessionMap = externalContext.getSessionMap();
+ sessionMap.put(FLASH_RENDER_MAP_TOKEN, tokenValue);
+ }
}
}
@@ -757,21 +767,31 @@ public class FlashImpl extends Flash
private String _getRenderFlashMapTokenFromPreviousRequest(ExternalContext externalContext)
{
String tokenValue = null;
- HttpServletResponse httpResponse = ExternalContextUtils.getHttpServletResponse(externalContext);
- if (httpResponse != null)
+ ClientWindow clientWindow = externalContext.getClientWindow();
+ if (clientWindow != null)
{
- //Use a cookie
- Cookie cookie = (Cookie) externalContext.getRequestCookieMap().get(FLASH_RENDER_MAP_TOKEN);
- if (cookie != null)
- {
- tokenValue = cookie.getValue();
- }
+ Map<String, Object> sessionMap = externalContext.getSessionMap();
+ tokenValue = (String) sessionMap.get(FLASH_RENDER_MAP_TOKEN+
+ SEPARATOR_CHAR+clientWindow.getId());
}
else
{
- //Use HttpSession or PortletSession object
- Map<String, Object> sessionMap = externalContext.getSessionMap();
- tokenValue = (String) sessionMap.get(FLASH_RENDER_MAP_TOKEN);
+ HttpServletResponse httpResponse = ExternalContextUtils.getHttpServletResponse(externalContext);
+ if (httpResponse != null)
+ {
+ //Use a cookie
+ Cookie cookie = (Cookie) externalContext.getRequestCookieMap().get(FLASH_RENDER_MAP_TOKEN);
+ if (cookie != null)
+ {
+ tokenValue = cookie.getValue();
+ }
+ }
+ else
+ {
+ //Use HttpSession or PortletSession object
+ Map<String, Object> sessionMap = externalContext.getSessionMap();
+ tokenValue = (String) sessionMap.get(FLASH_RENDER_MAP_TOKEN);
+ }
}
return tokenValue;
}
--
To stop receiving notification emails like this one, please contact
deki@apache.org.