[maven-release-plugin] copy for tag trinidad-1.2.15
diff --git a/pom.xml b/pom.xml
index b5277d8..cf2824d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,6 +17,29 @@
specific language governing permissions and limitations
under the License.
-->
+
+<!--
+This pom file has been optimized for Maven3. Usage of the various targets/tasks is below.
+
+Build:
+ mvn3 [install]
+ mvn3 clean install
+
+Prepare Release
+ mvn3 release:prepare -DprepareRelease=true
+
+Perform Release
+ mvn3 release:perform -DperformRelease=true
+
+Change Version Number (http://maven.apache.org/plugins/maven-release-plugin/examples/update-versions.html)
+ mvn3 release:update-versions
+ mvn3 release:update-versions -DautoVersionSubmodules=true
+
+Create A Branch (http://maven.apache.org/plugins/maven-release-plugin/examples/branch.html)
+ mvn3 release:branch -DbranchName=my-branch
+ mvn3 release:branch -DbranchName=my-branch -DupdateBranchVersions=true -DupdateWorkingCopyVersions=false
+-->
+
<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>
@@ -28,7 +51,7 @@
<parent>
<groupId>org.apache.myfaces</groupId>
<artifactId>myfaces</artifactId>
- <version>10</version>
+ <version>16</version>
</parent>
<groupId>org.apache.myfaces.trinidad</groupId>
@@ -51,6 +74,7 @@
<jsf-facelets.version>1.1.14</jsf-facelets.version>
<portlet-bridge.version>1.0.0-beta</portlet-bridge.version>
<commons-lang.version>2.4</commons-lang.version>
+ <commons-codec.version>1.3</commons-codec.version>
<pluto-embedded.version>1.0.1</pluto-embedded.version>
<!-- Testing -->
@@ -67,6 +91,18 @@
<!-- Other -->
<jdev.release>11.1.1.0.0</jdev.release>
+ <!-- Site deployment -->
+ <siteModule.path>trinidad-1.2</siteModule.path>
+ <site.mainDirectory>${user.home}/myfaces-site/checkout</site.mainDirectory>
+ <siteContent.path>${user.home}/myfaces-site/site/${siteModule.path}</siteContent.path>
+ <!-- it's a default location for performance reason (not checkout the content all the time)
+ you can override this value in your settings. -->
+ <scmCheckout.path>\${site.mainDirectory}/${siteModule.path}</scmCheckout.path>
+ <siteDeploy.url>file://${user.home}/myfaces-site/site/${siteModule.path}</siteDeploy.url>
+ <siteScmPublish.url>scm:svn:https://svn.apache.org/repos/asf/myfaces/site/publish/</siteScmPublish.url>
+
+ <checkstyle.skip>true</checkstyle.skip>
+
</properties>
<issueManagement>
@@ -173,6 +209,7 @@
</pluginRepository>
</pluginRepositories>
+ <!--
<distributionManagement>
<site>
<id>apache-site</id>
@@ -180,6 +217,14 @@
<url>scp://minotaur.apache.org/www/myfaces.apache.org/trinidad</url>
</site>
</distributionManagement>
+ -->
+ <distributionManagement>
+ <site>
+ <id>myfaces-local-staging</id>
+ <name>Apache Website</name>
+ <url>scp://localhost/${user.home}/myfaces-site/${siteModule.path}</url>
+ </site>
+ </distributionManagement>
<dependencyManagement>
<dependencies>
@@ -282,6 +327,12 @@
</dependency>
<dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>${commons-codec.version}</version>
+ </dependency>
+
+ <dependency>
<groupId>org.apache.myfaces.trinidad</groupId>
<artifactId>trinidad-build</artifactId>
<version>${project.version}</version>
@@ -357,11 +408,21 @@
</modules>
<build>
+
+ <!-- Since Maven 3.0, this is required to add scpexe as protocol for deploy. -->
+ <extensions>
+ <extension>
+ <groupId>org.apache.maven.wagon</groupId>
+ <artifactId>wagon-ssh-external</artifactId>
+ <version>1.0-beta-7</version>
+ </extension>
+ </extensions>
+
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-site-plugin</artifactId>
- <!--version>3.0-beta-3</version-->
+ <version>3.3</version>
<inherited>true</inherited>
<dependencies>
<dependency>
@@ -371,12 +432,50 @@
</dependency>
</dependencies>
<configuration>
+ <stagingRepositoryId>myfaces-local-staging</stagingRepositoryId>
+ <stagingSiteURL>${siteDeploy.url}</stagingSiteURL>
<outputEncoding>UTF-8</outputEncoding>
+ <reportPlugins>
+ <!--plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <version>2.0</version>
+ <configuration>
+ <threshold>Low</threshold>
+ </configuration>
+ </plugin-->
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rat-maven-plugin</artifactId>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>2.0.1</version>
+ </plugin>
+
+ <!--plugin>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>2.3</version>
+ <configuration>
+ <rulesets>
+ <ruleset>/rulesets/basic.xml</ruleset>
+ <ruleset>/rulesets/unusedcode.xml</ruleset>
+ </rulesets>
+ <linkXref>true</linkXref>
+ <minimumTokens>100</minimumTokens>
+ <targetJdk>${jdk.version}</targetJdk>
+ </configuration>
+ </plugin -->
+ </reportPlugins>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
+ <version>2.17</version>
<inherited>true</inherited>
<configuration>
<!-- set the forkMode to "always" to validate new tests,
@@ -459,6 +558,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<inherited>true</inherited>
+ <version>2.6</version>
<configuration>
<targetJdk>${jdk.version}</targetJdk>
</configuration>
@@ -523,11 +623,61 @@
<jdkLevel>5.0</jdkLevel>
</configuration>
</plugin>
-
+ <!-- Begin dependency fix for .md5 and .sha1 -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5.3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.6</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.8.2</version>
+ </plugin>
+ <!-- End -->
+
</plugins>
</pluginManagement>
<plugins>
+ <!--
+ Trinidad must now be built with a minimum of Maven 3.0 and Java 5.0 because
+ of some oddities with the checkstyle plugin
+ -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.0.1</version>
+ <executions>
+ <execution>
+ <id>enforce-maven</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <requireJavaVersion>
+ <message>Apache MyFaces Trinidad 1.2 needs to be compiled with Java 5</message>
+ <version>1.5</version>
+ </requireJavaVersion>
+ <requireMavenVersion>
+ <!-- Require AT LEAST Maven 3.0 or higher -->
+ <version>[${maven.min-version},)</version>
+ </requireMavenVersion>
+ <requireJavaVersion>
+ <message>Apache MyFaces Trinidad 2 needs to be compiled with at least JDK ${jdk.min-version}</message>
+ <version>[${jdk.min-version},)</version>
+ </requireJavaVersion>
+ </rules>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -585,6 +735,20 @@
</execution>
</executions>
</plugin>
+
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-publish-plugin</artifactId>
+ <version>1.0-beta-2</version>
+ <configuration>
+ <pubScmUrl>${siteScmPublish.url}</pubScmUrl>
+ <tryUpdate>true</tryUpdate>
+ <checkoutDirectory>${scmCheckout.path}</checkoutDirectory>
+ <content>\${siteContent.path}</content>
+ </configuration>
+ </plugin>
+
</plugins>
</build>
@@ -663,19 +827,94 @@
NOTE that for the maven lifecycle invoked by the release plugin, -Papache-release will
be added automatically because of the config in apache-parent-7.
-->
+ <!--
<profile>
<id>apache-release</id>
<modules>
<module>trinidad-assembly</module>
</modules>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</profile>
+ -->
+
+ <profile>
+ <id>prepare-release</id>
+ <activation>
+ <property>
+ <name>prepareRelease</name>
+ </property>
+ </activation>
+ <modules>
+ <module>trinidad-assembly</module>
+ </modules>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <configuration>
+ <arguments>-DprepareRelease</arguments>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>perform-release</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <modules>
+ <module>trinidad-assembly</module>
+ </modules>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <configuration>
+ <arguments>-Papache-release -DperformRelease</arguments>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
<profile>
- <id>partial-lifecycle</id>
- <modules>
- <module>trinidad-partial-lifecycle</module>
- </modules>
+ <id>enableRat</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</profile>
<!--
diff --git a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/CollectionModel.java b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/CollectionModel.java
index bfb83e1..9a51f90 100644
--- a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/CollectionModel.java
+++ b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/CollectionModel.java
@@ -143,11 +143,9 @@
}
/**
- * Gets the rowData at the given row key.
- * This method makes the given row current and calls
- * {@link #getRowData()}.
- * Finally, the row that was current before this method was called
- * is made current again.
+ * Returns the rowData for the given rowKey without changing model currency.
+ * Implementations may choose to implement this behavior by saving and restoring the currency.
+ *
* @see CollectionModel#getRowData()
* @param rowKey the row key of the row to get data from.
* @return the data for the given row.
diff --git a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ExternalContextUtils.java b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ExternalContextUtils.java
index 51673b3..6cfc1b7 100644
--- a/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ExternalContextUtils.java
+++ b/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ExternalContextUtils.java
@@ -317,6 +317,49 @@
}
/**
+ * Returns the scheme of the current request, or "unknown" if
+ * the request scheme cannot be determined.
+ *
+ * @param ec the current external context
+ * @return A string containing the current request scheme, or "unknown".
+ */
+ public static String getRequestScheme(ExternalContext ec)
+ {
+ if (isPortlet(ec))
+ {
+ return _getPortletRequestScheme(ec);
+ }
+
+ return _getServletRequestScheme(ec);
+ }
+
+ private static String _getPortletRequestScheme(ExternalContext ec)
+ {
+ try
+ {
+ return (String) _runMethod(ec.getContext(), "getScheme");
+ }
+ catch (Exception e)
+ {
+ _LOG.severe(e);
+ }
+
+ return _SCHEME_UNKNOWN;
+ }
+
+ private static String _getServletRequestScheme(ExternalContext ec)
+ {
+ Object request = ec.getRequest();
+
+ if (request instanceof ServletRequest)
+ {
+ return ((ServletRequest)request).getScheme();
+ }
+
+ return _SCHEME_UNKNOWN;
+ }
+
+ /**
* Returns the character encoding or <code>null</code> if there isn't any
*
* @param ec the current external context
@@ -586,6 +629,10 @@
private static final TrinidadLogger _LOG = TrinidadLogger
.createTrinidadLogger(ExternalContextUtils.class);
+ // getRequestScheme() return value in the event that we cannot
+ // determine the request scheme.
+ private static final String _SCHEME_UNKNOWN = "unknown";
+
// =-= Scott O'Bryan =-=
// Performance enhancement. These will be needed anyway, let's not get them every time.
private static final Class<?> _PORTLET_ACTION_REQUEST_CLASS;
diff --git a/trinidad-assembly/pom.xml b/trinidad-assembly/pom.xml
index c6f2518..4989860 100644
--- a/trinidad-assembly/pom.xml
+++ b/trinidad-assembly/pom.xml
@@ -35,28 +35,6 @@
<build>
<plugins>
<plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>2.2</version>
- <executions>
- <execution>
- <id>make_assembly_trinidad</id>
- <configuration>
- <descriptors>
- <descriptor>src/main/assembly/dep.xml</descriptor>
- </descriptors>
- <appendAssemblyId>true</appendAssemblyId> <!-- adds "-bin" and "-src" -->
- <tarLongFileMode>gnu</tarLongFileMode>
- </configuration>
- <phase>package</phase>
- <goals>
- <goal>single</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <!-- todo: what does this do and how is it activated? -->
- <plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>dependency-maven-plugin</artifactId>
<executions>
@@ -116,7 +94,6 @@
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
- <version>2.2</version>
<executions>
<execution>
<id>make_assembly_trinidad</id>
@@ -124,8 +101,11 @@
<descriptors>
<descriptor>src/main/assembly/dep.xml</descriptor>
</descriptors>
- <appendAssemblyId>true</appendAssemblyId> <!-- adds "-bin" and "-src" -->
+ <finalName>trinidad-assembly-${project.version}-dist</finalName>
+ <appendAssemblyId>false</appendAssemblyId> <!-- adds "-bin" and "-src" -->
<tarLongFileMode>gnu</tarLongFileMode>
+ <outputDirectory>target/assembly/out</outputDirectory>
+ <workDirectory>target/assembly/work</workDirectory>
</configuration>
<phase>package</phase>
<goals>
@@ -134,6 +114,35 @@
</execution>
</executions>
</plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>target/assembly/out/trinidad-assembly-${project.version}-dist.zip</file>
+ <type>zip</type>
+ <classifier>dist</classifier>
+ </artifact>
+ <artifact>
+ <file>target/assembly/out/trinidad-assembly-${project.version}-dist.tar.gz</file>
+ <type>tar.gz</type>
+ <classifier>dist</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
diff --git a/trinidad-examples/pom.xml b/trinidad-examples/pom.xml
index d7322a1..a194437 100644
--- a/trinidad-examples/pom.xml
+++ b/trinidad-examples/pom.xml
@@ -89,14 +89,67 @@
mvn release:prepare -Papache-releae
-->
+ <!--
<profile>
<id>apache-release</id>
-
<modules>
<module>trinidad-example-assembly</module>
</modules>
</profile>
+ -->
+ <profile>
+ <id>prepare-release</id>
+ <activation>
+ <property>
+ <name>prepareRelease</name>
+ </property>
+ </activation>
+ <modules>
+ <module>trinidad-example-assembly</module>
+ </modules>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <configuration>
+ <arguments>-DprepareRelease</arguments>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>perform-release</id>
+ <activation>
+ <property>
+ <name>performRelease</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <modules>
+ <module>trinidad-example-assembly</module>
+ </modules>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <configuration>
+ <arguments>-Papache-release -DperformRelease</arguments>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <!--
+ This profile activates MyFaces as the release to use for these demos. By default
+ MyFaces is used when these examples are run in Jetty and/or used with the -PincludeJSF
+ flag. To invoke this profile, simply do not include a -Djsf= property on your maven
+ command line. Execute this profile like this:
+
+ mvn -PjettyConfig jetty:run
+ -->
<profile>
<id>jettyConfig</id>
<dependencyManagement>
diff --git a/trinidad-examples/trinidad-example-assembly/pom.xml b/trinidad-examples/trinidad-example-assembly/pom.xml
index 143bf7f..38e163d 100644
--- a/trinidad-examples/trinidad-example-assembly/pom.xml
+++ b/trinidad-examples/trinidad-example-assembly/pom.xml
@@ -28,6 +28,7 @@
<groupId>org.apache.myfaces.trinidad</groupId>
<artifactId>trinidad</artifactId>
<version>1.2.15</version>
+ <relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>trinidad-example-assembly</artifactId>
@@ -111,6 +112,35 @@
</execution>
</executions>
</plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>target/trinidad-example-assembly-${project.version}-example.zip</file>
+ <type>zip</type>
+ <classifier>example</classifier>
+ </artifact>
+ <artifact>
+ <file>target/trinidad-example-assembly-${project.version}-example.tar.gz</file>
+ <type>tar.gz</type>
+ <classifier>example</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
diff --git a/trinidad-impl/pom.xml b/trinidad-impl/pom.xml
index a082cf5..ca4c054 100644
--- a/trinidad-impl/pom.xml
+++ b/trinidad-impl/pom.xml
@@ -75,6 +75,12 @@
<groupId>org.apache.myfaces.trinidad</groupId>
<artifactId>trinidad-api</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <scope>compile</scope>
+ </dependency>
<dependency>
<groupId>com.sun.facelets</groupId>
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java
index cc8ce8d..92777b5 100644
--- a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/CoreResponseStateManager.java
@@ -19,6 +19,7 @@
package org.apache.myfaces.trinidadinternal.renderkit.core;
import javax.faces.application.StateManager;
+import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.ResponseStateManager;
@@ -47,6 +48,7 @@
import org.apache.myfaces.trinidad.util.Base64OutputStream;
import org.apache.myfaces.trinidad.util.ClassLoaderUtils;
import org.apache.myfaces.trinidadinternal.util.ObjectInputStreamResolveClass;
+import org.apache.myfaces.trinidadinternal.util.StateUtils;
/**
* ResponseStateManager implementation for the Core RenderKit.
@@ -78,7 +80,7 @@
// out twice
// rw.writeAttribute("id", VIEW_STATE_PARAM, null);
- String s = encodeSerializedViewAsString(serializedView);
+ String s = encodeSerializedViewAsString(context, serializedView);
rw.writeAttribute("value", s, null);
rw.endElement("input");
@@ -95,13 +97,16 @@
}
- protected String encodeSerializedViewAsString(
+ protected String encodeSerializedViewAsString(FacesContext context,
StateManager.SerializedView serializedView) throws IOException
{
if ((serializedView.getState() == null) &&
(serializedView.getStructure() instanceof String))
- return _TOKEN_PREFIX + serializedView.getStructure();
+ return _TOKEN_PREFIX + StateUtils.construct(serializedView.getStructure(), context.getExternalContext());
+ return StateUtils.construct(
+ new Object[]{serializedView.getStructure(),serializedView.getState()}, context.getExternalContext());
+ /*
StringWriter sw = new StringWriter();
BufferedWriter bw = new BufferedWriter(sw);
Base64OutputStream b64_out = new Base64OutputStream(bw);
@@ -120,7 +125,7 @@
String retVal = sw.toString();
assert(!retVal.startsWith(_TOKEN_PREFIX));
- return retVal;
+ return retVal;*/
}
@Override
@@ -154,9 +159,10 @@
private Object[] _restoreSerializedView(
FacesContext context)
{
- Map<String, Object> requestMap =
- context.getExternalContext().getRequestMap();
+ ExternalContext external = context.getExternalContext();
+ Map<String, Object> requestMap = external.getRequestMap();
+
Object[] view = (Object[]) requestMap.get(_CACHED_SERIALIZED_VIEW);
if (view == null)
{
@@ -172,37 +178,43 @@
if (stateString.startsWith(_TOKEN_PREFIX))
{
String tokenString = stateString.substring(_TOKEN_PREFIX.length());
- view = new Object[]{tokenString, null};
+ view = new Object[]{StateUtils.reconstruct(tokenString, context.getExternalContext()), null};
}
// Nope, let's look for a regular state field
else
{
- StringReader sr = new StringReader(stateString);
- BufferedReader br = new BufferedReader(sr);
- Base64InputStream b64_in = new Base64InputStream(br);
+ if (stateString != null)
+ {
+ view = (Object[]) StateUtils.reconstruct(stateString, context.getExternalContext());
+ /*
+ StringReader sr = new StringReader(stateString);
+ BufferedReader br = new BufferedReader(sr);
+ Base64InputStream b64_in = new Base64InputStream(br);
- try
- {
- ObjectInputStream ois;
- ois = new ObjectInputStreamResolveClass( new GZIPInputStream( b64_in, _BUFFER_SIZE ));
+ try
+ {
+ ObjectInputStream ois;
+ ois = new ObjectInputStreamResolveClass( new GZIPInputStream( b64_in, _BUFFER_SIZE ));
- Object structure = ois.readObject();
- Object state = ois.readObject();
- ois.close();
- view = new Object[]{structure, state};
- }
- catch (OptionalDataException ode)
- {
- _LOG.severe(ode);
- }
- catch (ClassNotFoundException cnfe)
- {
- _LOG.severe(cnfe);
- }
- catch (IOException ioe)
- {
- _LOG.severe(ioe);
+ Object structure = ois.readObject();
+ Object state = ois.readObject();
+ ois.close();
+ view = new Object[]{structure, state};
+ }
+ catch (OptionalDataException ode)
+ {
+ _LOG.severe(ode);
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ _LOG.severe(cnfe);
+ }
+ catch (IOException ioe)
+ {
+ _LOG.severe(ioe);
+ }
+ */
}
}
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java
index c74f34e..bd2246f 100644
--- a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java
@@ -24,6 +24,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
+import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import org.apache.myfaces.trinidad.context.AccessibilityProfile;
@@ -33,6 +34,7 @@
import org.apache.myfaces.trinidad.skin.Icon;
import org.apache.myfaces.trinidad.skin.Skin;
import org.apache.myfaces.trinidad.style.Styles;
+import org.apache.myfaces.trinidad.util.ExternalContextUtils;
import org.apache.myfaces.trinidadinternal.agent.TrinidadAgent;
import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.HtmlRenderer;
import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.StyleSheetRenderer;
@@ -175,6 +177,24 @@
{
return CoreRenderKit.OUTPUT_MODE_PORTLET.equals(_arc.getOutputMode());
}
+
+ @Override
+ public boolean isRequestSecure()
+ {
+ if (_isRequestSecure == null)
+ {
+ String scheme = _getRequestScheme();
+ _isRequestSecure = "https".equals(scheme);
+ }
+ return _isRequestSecure;
+ }
+
+ static private String _getRequestScheme()
+ {
+ FacesContext context = FacesContext.getCurrentInstance();
+ ExternalContext external = context.getExternalContext();
+ return ExternalContextUtils.getRequestScheme(external);
+ }
/**
*
@@ -286,6 +306,8 @@
private StyleProvider _styleProvider;
private Styles _styles;
private Boolean _isDisableStyleCompression;
+ private Boolean _isRequestSecure;
+
static private final String _SKIN_ID_PARAM =
"org.apache.myfaces.trinidad.skin.id";
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SelectRangeChoiceBarRenderer.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SelectRangeChoiceBarRenderer.java
index bdc2471..c88cce1 100644
--- a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SelectRangeChoiceBarRenderer.java
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/SelectRangeChoiceBarRenderer.java
@@ -375,6 +375,11 @@
// make sure the next range exists in the data model.
hasNextRecords = isRowAvailable(component, (int)nextValue-1);
}
+
+ if (!hasNextRecords)
+ {
+ nextRecords = 0;
+ }
boolean showBackButton = hasBackRecords || showDisabledNavigation;
boolean showNextButton = hasNextRecords || showDisabledNavigation;
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleContext.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleContext.java
index 8f5107a..b8a5750 100644
--- a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleContext.java
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleContext.java
@@ -54,4 +54,9 @@
public boolean isPortletMode();
public boolean isDisableStyleCompression();
public boolean isDirty();
+
+ /**
+ * @return true if the current request is secure (an https request), false otherwise
+ */
+ public boolean isRequestSecure();
}
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java
index 84c5571..08df19a 100644
--- a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java
@@ -268,6 +268,12 @@
buffer.append(_PORTLET);
}
+
+ if (context.isRequestSecure())
+ {
+ buffer.append(_NAME_SEPARATOR);
+ buffer.append(_SECURE);
+ }
buffer.append(_CSS_EXTENSION);
@@ -1084,7 +1090,8 @@
agent.getAgentOS(),
!context.isDisableStyleCompression(),
accProfile,
- context.isPortletMode());
+ context.isPortletMode(),
+ context.isRequestSecure());
}
@Override
@@ -1097,7 +1104,8 @@
(_browser.ordinal() << 2) ^
(_platform << 8) ^
(_short ? 1 : 0) ^
- (_portlet ? 1:0);
+ ((_portlet ? 1:0) << 1) ^
+ ((_secureRequest ? 1: 0) << 3);
if (_locale != null) _hashCode ^= _locale.hashCode();
if (_accProfile != null) _hashCode ^= _accProfile.hashCode();
@@ -1124,7 +1132,8 @@
(_portlet == key._portlet) &&
(_direction == key._direction) &&
(_browser == key._browser) &&
- (_platform == key._platform))
+ (_platform == key._platform) &&
+ (_secureRequest == key._secureRequest))
{
// now check the optional objects
if ((_version == null) || _version.equals(key._version))
@@ -1144,7 +1153,8 @@
int platform,
boolean useShort,
AccessibilityProfile accessibilityProfile,
- boolean portlet
+ boolean portlet,
+ boolean secure
)
{
// Make sure direction is non-null
@@ -1162,6 +1172,7 @@
_short = useShort;
_accProfile = accessibilityProfile;
_portlet = portlet;
+ _secureRequest = secure;
}
//is immutable, we should cache this, will make things faster in the long run
@@ -1176,6 +1187,7 @@
private boolean _short; // Do we use short style classes?
private AccessibilityProfile _accProfile;
private boolean _portlet; //kind of a hack but tells whether this was created in portal mode
+ private boolean _secureRequest;
}
/**
@@ -1214,6 +1226,7 @@
System.arraycopy(styleSheets, 0, _styleSheets, 0, styleSheets.length);
_short = true;
_portlet = context.isPortletMode();
+ _secureRequest = context.isRequestSecure();
}
@Override
@@ -1228,6 +1241,7 @@
if ((_short != key._short) ||
(_portlet != key._portlet) ||
+ (_secureRequest != key._secureRequest) ||
(_styleSheets.length != key._styleSheets.length))
return false;
@@ -1254,7 +1268,8 @@
{
_hashCode = Arrays.hashCode(_styleSheets) ^
(_short ? 1 : 0) ^
- (_portlet ? 1 : 0);
+ (_portlet ? 1 : 0) ^
+ ((_secureRequest ? 1: 0) << 3);
_noHash = false;
}
@@ -1268,6 +1283,7 @@
private StyleSheetNode[] _styleSheets;
private boolean _portlet;
private boolean _short; // Do we use short style classes?
+ private boolean _secureRequest;
}
@@ -1585,6 +1601,7 @@
private static final char _NAME_SEPARATOR = '-';
private static final String _COMPRESSED = "cmp";
private static final String _PORTLET = "prtl";
+ private static final String _SECURE = "s";
/** Extension for CSS files */
private static final String _CSS_EXTENSION = ".css";
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ClassLoaderUtils.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ClassLoaderUtils.java
new file mode 100644
index 0000000..3d8c3bb
--- /dev/null
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ClassLoaderUtils.java
@@ -0,0 +1,394 @@
+/*
+ * 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.trinidadinternal.util;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.io.InputStreamReader;
+
+import java.net.URL;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.faces.FacesException;
+
+/**
+ * Utility methods for accessing classes and resources using an appropriate
+ * class loader.
+ *
+ * @version $Revision$ $Date$
+ */
+public final class ClassLoaderUtils
+{
+ // Utility class only, no instances
+ private ClassLoaderUtils()
+ {
+ }
+
+ /**
+ * Loads the class with the specified name. For Java 2 callers, the
+ * current thread's context class loader is preferred, falling back on the
+ * system class loader of the caller when the current thread's context is not
+ * set, or the caller is pre Java 2.
+ *
+ * @param name the name of the class
+ * @return the resulting <code>Class</code> object
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public static Class<?> loadClass(
+ String name) throws ClassNotFoundException
+ {
+ return loadClass(name, null);
+ }
+
+ /**
+ * Locates the resource with the specified name. For Java 2 callers, the
+ * current thread's context class loader is preferred, falling back on the
+ * system class loader of the caller when the current thread's context is not
+ * set, or the caller is pre Java 2.
+ *
+ * @param name the name of the resource
+ * @return the resulting <code>URL</code> object
+ */
+ public static URL getResource(
+ String name)
+ {
+ return getResource(name, null);
+ }
+
+ /**
+ * Locates the stream resource with the specified name. For Java 2 callers,
+ * the current thread's context class loader is preferred, falling back on
+ * the system class loader of the caller when the current thread's context is
+ * not set, or the caller is pre Java 2.
+ *
+ * @param name the name of the resource
+ * @return the resulting <code>InputStream</code> object
+ */
+ public static InputStream getResourceAsStream(
+ String name)
+ {
+ return getResourceAsStream(name, null);
+ }
+
+ /**
+ * Loads the class with the specified name. For Java 2 callers, the
+ * current thread's context class loader is preferred, falling back on the
+ * class loader of the caller when the current thread's context is not set,
+ * or the caller is pre Java 2. If the callerClassLoader is null, then
+ * fall back on the system class loader.
+ *
+ * @param name the name of the class
+ * @param callerClassLoader the calling class loader context
+ * @return the resulting <code>Class</code> object
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public static Class<?> loadClass(
+ String name,
+ ClassLoader callerClassLoader) throws ClassNotFoundException
+ {
+ Class<?> clazz = null;
+
+ try
+ {
+ ClassLoader loader = getContextClassLoader();
+
+ if (loader != null)
+ {
+ clazz = loader.loadClass(name);
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ // treat as though loader not set
+ }
+
+ if (clazz == null)
+ {
+ if (callerClassLoader != null)
+ {
+ clazz = callerClassLoader.loadClass(name);
+ }
+ else
+ {
+ clazz = Class.forName(name);
+ }
+ }
+
+ return clazz;
+ }
+
+ /**
+ * Locates the resource with the specified name. For Java 2 callers, the
+ * current thread's context class loader is preferred, falling back on the
+ * class loader of the caller when the current thread's context is not set,
+ * or the caller is pre Java 2. If the callerClassLoader is null, then
+ * fall back on the system class loader.
+ *
+ * @param name the name of the resource
+ * @param callerClassLoader the calling class loader context
+ * @return the resulting <code>URL</code> object
+ */
+ public static URL getResource(
+ String name,
+ ClassLoader callerClassLoader)
+ {
+ _checkResourceName(name);
+
+ URL url = null;
+
+ ClassLoader loader = getContextClassLoader();
+
+ if (loader != null)
+ {
+ url = loader.getResource(name);
+ }
+
+ if (url == null)
+ {
+ if (callerClassLoader != null)
+ {
+ url = callerClassLoader.getResource(name);
+ }
+ else
+ {
+ url = ClassLoader.getSystemResource(name);
+ }
+ }
+
+ return url;
+ }
+
+ /**
+ * Locates the resource stream with the specified name. For Java 2 callers,
+ * the current thread's context class loader is preferred, falling back on
+ * the class loader of the caller when the current thread's context is not
+ * set, or the caller is pre Java 2. If the callerClassLoader is null, then
+ * fall back on the system class loader.
+ *
+ * @param name the name of the resource
+ * @param callerClassLoader the calling class loader context
+ * @return the resulting <code>InputStream</code> object
+ */
+ public static InputStream getResourceAsStream(
+ String name,
+ ClassLoader callerClassLoader)
+ {
+ _checkResourceName(name);
+
+ InputStream stream = null;
+
+ ClassLoader loader = getContextClassLoader();
+
+ if (loader != null)
+ {
+ stream = loader.getResourceAsStream(name);
+ }
+
+ if (stream == null)
+ {
+ if (callerClassLoader != null)
+ {
+ stream = callerClassLoader.getResourceAsStream(name);
+ }
+ else
+ {
+ stream = ClassLoader.getSystemResourceAsStream(name);
+ }
+ }
+
+ return stream;
+ }
+
+ /**
+ * Dynamically accesses the current context class loader.
+ * Includes a check for priviledges against java2 security
+ * to ensure no security related exceptions are encountered.
+ * Returns null if there is no per-thread context class loader.
+ */
+ public static ClassLoader getContextClassLoader()
+ {
+ if (System.getSecurityManager() != null)
+ {
+ try
+ {
+ ClassLoader cl = AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>()
+ {
+ public ClassLoader run() throws PrivilegedActionException
+ {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ });
+ return cl;
+ }
+ catch (PrivilegedActionException pae)
+ {
+ throw new FacesException(pae);
+ }
+ }
+ else
+ {
+ return Thread.currentThread().getContextClassLoader();
+ }
+ }
+
+ /**
+ * Instantiate a service from a file in /META-INF/services.
+ * <P>
+ * The following is an excerpt from the JAR File specification:
+ * A service provider identifies itself by placing a provider-configuration file
+ * in the resource directory META-INF/services.
+ * The file's name should consist of the fully-qualified name of the abstract service class.
+ * The file should contain a newline-separated list of unique concrete provider-class names.
+ * Space and tab characters, as well as blank lines, are ignored. The comment character is '#' (0x23);
+ * on each line all characters following the first comment character are ignored.
+ * The file must be encoded in UTF-8.
+ *
+ * @param service the classname of the abstract service class.
+ * eg: javax.servlet.Filter
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> List<T> getServices(String service)
+ {
+ String serviceUri ="META-INF/services/" + service;
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ try
+ {
+ Enumeration<URL> urls = loader.getResources(serviceUri);
+ if (urls.hasMoreElements())
+ {
+ List<T> services = new ArrayList<T>(1);
+ Set<String> keys = new HashSet<String>(20);
+ do
+ {
+ URL url = urls.nextElement();
+
+ if (_LOG.isLoggable(Level.FINEST))
+ {
+ _LOG.finest("Processing: " + url);
+ }
+ try
+ {
+ BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
+ try
+ {
+ while(true)
+ {
+ String line = in.readLine();
+ if (line == null)
+ {
+ break;
+ }
+
+ String className = _parseLine(line);
+
+ if(className!=null && keys.add(className))
+ {
+ T instance = (T) _getClass(loader, className);
+ services.add(instance);
+ }
+ }
+ }
+ finally
+ {
+ in.close();
+ }
+ }
+ catch (Exception e)
+ {
+ if (_LOG.isLoggable(Level.WARNING))
+ {
+ _LOG.log(Level.WARNING, "Error parsing URL: " + url, e);
+ }
+ }
+ }
+ while(urls.hasMoreElements());
+
+ if (services.size() == 1)
+ {
+ return Collections.singletonList(services.get(0));
+ }
+
+ return Collections.unmodifiableList(services);
+ }
+ }
+ catch (IOException e)
+ {
+ if (_LOG.isLoggable(Level.SEVERE))
+ {
+ _LOG.log(Level.SEVERE, "Error loading Resource: " + serviceUri, e);
+ }
+ }
+
+ return Collections.emptyList();
+ }
+
+ private static String _parseLine(String line)
+ {
+ // Eliminate any comments
+ int hashIndex = line.indexOf('#');
+ if (hashIndex >= 0)
+ {
+ line = line.substring(0, hashIndex);
+ }
+
+ // and any whitespace
+ line = line.trim();
+ if (line.length() > 0)
+ {
+ return line;
+ }
+
+ return null;
+ }
+
+ private static Object _getClass(ClassLoader loader, String className)
+ throws ClassNotFoundException, InstantiationException,
+ IllegalAccessException
+ {
+ Class<?> clazz = loader.loadClass(className);
+ return clazz.newInstance();
+ }
+
+ private static void _checkResourceName(String name)
+ {
+ if ((name != null) && name.startsWith("/"))
+ {
+ if (_LOG.isLoggable(Level.WARNING))
+ {
+ _LOG.log(Level.WARNING, "Resource name not portable: " +name);
+ }
+ }
+ }
+
+ private static final Logger _LOG = Logger.getLogger(ClassLoaderUtils.class.getName());
+}
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ClassUtils.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ClassUtils.java
new file mode 100755
index 0000000..25a7b77
--- /dev/null
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/ClassUtils.java
@@ -0,0 +1,661 @@
+/*
+ * 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.trinidadinternal.util;
+
+import javax.el.ExpressionFactory;
+import javax.faces.FacesException;
+import javax.faces.context.FacesContext;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+public final class ClassUtils
+{
+ //~ Static fields/initializers -----------------------------------------------------------------
+
+ //private static final Log log = LogFactory.getLog(ClassUtils.class);
+ private static final Logger log = Logger.getLogger(ClassUtils.class.getName());
+
+ public static final Class BOOLEAN_ARRAY_CLASS = boolean[].class;
+ public static final Class BYTE_ARRAY_CLASS = byte[].class;
+ public static final Class CHAR_ARRAY_CLASS = char[].class;
+ public static final Class SHORT_ARRAY_CLASS = short[].class;
+ public static final Class INT_ARRAY_CLASS = int[].class;
+ public static final Class LONG_ARRAY_CLASS = long[].class;
+ public static final Class FLOAT_ARRAY_CLASS = float[].class;
+ public static final Class DOUBLE_ARRAY_CLASS = double[].class;
+ public static final Class OBJECT_ARRAY_CLASS = Object[].class;
+ public static final Class BOOLEAN_OBJECT_ARRAY_CLASS = Boolean[].class;
+ public static final Class BYTE_OBJECT_ARRAY_CLASS = Byte[].class;
+ public static final Class CHARACTER_OBJECT_ARRAY_CLASS = Character[].class;
+ public static final Class SHORT_OBJECT_ARRAY_CLASS = Short[].class;
+ public static final Class INTEGER_OBJECT_ARRAY_CLASS = Integer[].class;
+ public static final Class LONG_OBJECT_ARRAY_CLASS = Long[].class;
+ public static final Class FLOAT_OBJECT_ARRAY_CLASS = Float[].class;
+ public static final Class DOUBLE_OBJECT_ARRAY_CLASS = Double[].class;
+ public static final Class STRING_OBJECT_ARRAY_CLASS = String[].class;
+
+ //public static ClassLoaderExtension [] classLoadingExtensions = new ClassLoaderExtension[0];
+
+
+
+ public static final Map COMMON_TYPES = new HashMap(64);
+ static
+ {
+ COMMON_TYPES.put("byte", Byte.TYPE);
+ COMMON_TYPES.put("char", Character.TYPE);
+ COMMON_TYPES.put("double", Double.TYPE);
+ COMMON_TYPES.put("float", Float.TYPE);
+ COMMON_TYPES.put("int", Integer.TYPE);
+ COMMON_TYPES.put("long", Long.TYPE);
+ COMMON_TYPES.put("short", Short.TYPE);
+ COMMON_TYPES.put("boolean", Boolean.TYPE);
+ COMMON_TYPES.put("void", Void.TYPE);
+ COMMON_TYPES.put("java.lang.Object", Object.class);
+ COMMON_TYPES.put("java.lang.Boolean", Boolean.class);
+ COMMON_TYPES.put("java.lang.Byte", Byte.class);
+ COMMON_TYPES.put("java.lang.Character", Character.class);
+ COMMON_TYPES.put("java.lang.Short", Short.class);
+ COMMON_TYPES.put("java.lang.Integer", Integer.class);
+ COMMON_TYPES.put("java.lang.Long", Long.class);
+ COMMON_TYPES.put("java.lang.Float", Float.class);
+ COMMON_TYPES.put("java.lang.Double", Double.class);
+ COMMON_TYPES.put("java.lang.String", String.class);
+
+ COMMON_TYPES.put("byte[]", BYTE_ARRAY_CLASS);
+ COMMON_TYPES.put("char[]", CHAR_ARRAY_CLASS);
+ COMMON_TYPES.put("double[]", DOUBLE_ARRAY_CLASS);
+ COMMON_TYPES.put("float[]", FLOAT_ARRAY_CLASS);
+ COMMON_TYPES.put("int[]", INT_ARRAY_CLASS);
+ COMMON_TYPES.put("long[]", LONG_ARRAY_CLASS);
+ COMMON_TYPES.put("short[]", SHORT_ARRAY_CLASS);
+ COMMON_TYPES.put("boolean[]", BOOLEAN_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Object[]", OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Boolean[]", BOOLEAN_OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Byte[]", BYTE_OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Character[]", CHARACTER_OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Short[]", SHORT_OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Integer[]", INTEGER_OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Long[]", LONG_OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Float[]", FLOAT_OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.Double[]", DOUBLE_OBJECT_ARRAY_CLASS);
+ COMMON_TYPES.put("java.lang.String[]", STRING_OBJECT_ARRAY_CLASS);
+ // array of void is not a valid type
+ }
+
+ /** utility class, do not instantiate */
+ private ClassUtils()
+ {
+ // utility class, disable instantiation
+ }
+
+ //~ Methods ------------------------------------------------------------------------------------
+
+ /*
+ public synchronized static void addClassLoadingExtension(ClassLoaderExtension extension, boolean top)
+ {
+ /**
+ * now at the first look this looks somewhat strange
+ * but to get the best performance access we assign new native
+ * arrays to our static variable
+ *
+ * we have to synchronized nevertheless because if two threads try to register
+ * loaders at the same time none of them should get lost
+ */
+ /*
+ ClassLoaderExtension [] retVal = new ClassLoaderExtension[classLoadingExtensions.length+1];
+ ArrayList extensions = new ArrayList(classLoadingExtensions.length+1);
+
+ if(!top)
+ {
+ extensions.addAll(Arrays.asList(classLoadingExtensions));
+ }
+ extensions.add(extension);
+ if(top)
+ {
+ extensions.addAll(Arrays.asList(classLoadingExtensions));
+ }
+
+ classLoadingExtensions = (ClassLoaderExtension []) extensions.toArray(retVal);
+ }*/
+
+ /**
+ * Tries a Class.loadClass with the context class loader of the current thread first and
+ * automatically falls back to the ClassUtils class loader (i.e. the loader of the
+ * myfaces.jar lib) if necessary.
+ *
+ * @param type fully qualified name of a non-primitive non-array class
+ * @return the corresponding Class
+ * @throws NullPointerException if type is null
+ * @throws ClassNotFoundException
+ */
+ public static Class classForName(String type)
+ throws ClassNotFoundException
+ {
+ //we now assign the array to safekeep the reference on
+ // the local variable stack, that way
+ //we can avoid synchronisation calls
+ /*
+ ClassLoaderExtension [] loaderPlugins = classLoadingExtensions;
+
+ int plugins = loaderPlugins.length;
+ for(int cnt = 0; cnt < loaderPlugins.length; cnt ++)
+ {
+ ClassLoaderExtension extension = loaderPlugins[cnt];
+ Class retVal = extension.forName(type);
+ if(retVal != null)
+ {
+ return retVal;
+ }
+ }
+ */
+
+ if (type == null)
+ {
+ throw new NullPointerException("type");
+ }
+ try
+ {
+ // Try WebApp ClassLoader first
+ return Class.forName(type,
+ false, // do not initialize for faster startup
+ getContextClassLoader());
+ }
+ catch (ClassNotFoundException ignore)
+ {
+ // fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib)
+ return Class.forName(type,
+ false, // do not initialize for faster startup
+ ClassUtils.class.getClassLoader());
+ }
+ }
+
+
+ /**
+ * Same as {@link #classForName(String)}, but throws a RuntimeException
+ * (FacesException) instead of a ClassNotFoundException.
+ *
+ * @return the corresponding Class
+ * @throws NullPointerException if type is null
+ * @throws FacesException if class not found
+ */
+ public static Class simpleClassForName(String type)
+ {
+ try
+ {
+ return classForName(type);
+ }
+ catch (ClassNotFoundException e)
+ {
+ log.log(Level.SEVERE, "Class " + type + " not found", e);
+ throw new FacesException(e);
+ }
+ }
+
+
+ /**
+ * Similar as {@link #classForName(String)}, but also supports primitive types
+ * and arrays as specified for the JavaType element in the JavaServer Faces Config DTD.
+ *
+ * @param type fully qualified class name or name of a primitive type, both optionally
+ * followed by "[]" to indicate an array type
+ * @return the corresponding Class
+ * @throws NullPointerException if type is null
+ * @throws ClassNotFoundException
+ */
+ public static Class javaTypeToClass(String type)
+ throws ClassNotFoundException
+ {
+ if (type == null)
+ {
+ throw new NullPointerException("type");
+ }
+
+ // try common types and arrays of common types first
+ Class clazz = (Class) COMMON_TYPES.get(type);
+ if (clazz != null)
+ {
+ return clazz;
+ }
+
+ int len = type.length();
+ if (len > 2 && type.charAt(len - 1) == ']' && type.charAt(len - 2) == '[')
+ {
+ String componentType = type.substring(0, len - 2);
+ Class componentTypeClass = classForName(componentType);
+ return Array.newInstance(componentTypeClass, 0).getClass();
+ }
+
+ return classForName(type);
+
+ }
+
+ /**
+ * This method is similar to shared ClassUtils.javaTypeToClass,
+ * but the default package for the type is java.lang
+ *
+ * @param type
+ * @return
+ * @throws ClassNotFoundException
+ */
+ public static Class javaDefaultTypeToClass(String type)
+ throws ClassNotFoundException
+ {
+ if (type == null)
+ {
+ throw new NullPointerException("type");
+ }
+
+ // try common types and arrays of common types first
+ Class clazz = (Class) ClassUtils.COMMON_TYPES.get(type);
+ if (clazz != null)
+ {
+ return clazz;
+ }
+
+ int len = type.length();
+ if (len > 2 && type.charAt(len - 1) == ']' && type.charAt(len - 2) == '[')
+ {
+ String componentType = type.substring(0, len - 2);
+ Class componentTypeClass = ClassUtils.classForName(componentType);
+ return Array.newInstance(componentTypeClass, 0).getClass();
+ }
+
+ if (type.indexOf('.') == -1)
+ {
+ type = "java.lang." + type;
+ }
+ return ClassUtils.classForName(type);
+ }
+
+ /**
+ * Same as {@link #javaTypeToClass(String)}, but throws a RuntimeException
+ * (FacesException) instead of a ClassNotFoundException.
+ *
+ * @return the corresponding Class
+ * @throws NullPointerException if type is null
+ * @throws FacesException if class not found
+ */
+ public static Class simpleJavaTypeToClass(String type)
+ {
+ try
+ {
+ return javaTypeToClass(type);
+ }
+ catch (ClassNotFoundException e)
+ {
+ log.log(Level.SEVERE, "Class " + type + " not found", e);
+ throw new FacesException(e);
+ }
+ }
+
+ public static URL getResource(String resource)
+ {
+ URL url = getContextClassLoader().getResource(resource);
+ if (url == null)
+ {
+ url = ClassUtils.class.getClassLoader().getResource(resource);
+ }
+ return url;
+ }
+
+ public static InputStream getResourceAsStream(String resource)
+ {
+ InputStream stream = getContextClassLoader()
+ .getResourceAsStream(resource);
+ if (stream == null)
+ {
+ // fallback
+ stream = ClassUtils.class.getClassLoader().getResourceAsStream(resource);
+ }
+ return stream;
+ }
+
+ /**
+ * @param resource Name of resource(s) to find in classpath
+ * @param defaultObject The default object to use to determine the class loader
+ * (if none associated with current thread.)
+ * @return Iterator over URL Objects
+ */
+ public static Iterator getResources(String resource, Object defaultObject)
+ {
+ try
+ {
+ Enumeration resources = getCurrentLoader(defaultObject).getResources(resource);
+ List lst = new ArrayList();
+ while (resources.hasMoreElements())
+ {
+ lst.add(resources.nextElement());
+ }
+ return lst.iterator();
+ }
+ catch (IOException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ }
+
+
+ public static Object newInstance(String type)
+ throws FacesException
+ {
+ if (type == null)
+ {
+ return null;
+ }
+ return newInstance(simpleClassForName(type));
+ }
+
+ public static Object newInstance(String type, Class expectedType) throws FacesException
+ {
+ return newInstance(type, expectedType == null ? null : new Class[] {expectedType});
+ }
+
+ public static Object newInstance(String type, Class[] expectedTypes)
+ {
+ if (type == null)
+ {
+ return null;
+ }
+
+ Class clazzForName = simpleClassForName(type);
+
+ if(expectedTypes != null)
+ {
+ for (int i = 0, size = expectedTypes.length; i < size; i++)
+ {
+ if (!expectedTypes[i].isAssignableFrom(clazzForName))
+ {
+ throw new FacesException("'" + type + "' does not implement expected type '" + expectedTypes[i]
+ + "'");
+ }
+ }
+ }
+
+ return newInstance(clazzForName);
+ }
+
+ public static <T> T newInstance(Class<T> clazz)
+ throws FacesException
+ {
+ try
+ {
+ return clazz.newInstance();
+ }
+ catch(NoClassDefFoundError e)
+ {
+ log.log(Level.SEVERE, "Class : "+clazz.getName()+" not found.",e);
+ throw new FacesException(e);
+ }
+ catch (InstantiationException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ catch (IllegalAccessException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ }
+
+ public static <T> T newInstance(Class<T> clazz,
+ Class<?>[] constructorArgClasses,
+ Object... constructorArgs) throws NoSuchMethodException
+ {
+ if (constructorArgs.length == 0)
+ {
+ // no args given - use normal newInstance()
+ return newInstance(clazz);
+ }
+
+ // try to get a fitting constructor (throws NoSuchMethodException)
+ Constructor constructor = clazz.getConstructor(constructorArgClasses);
+
+ try
+ {
+ // actually create instance
+ return (T) constructor.newInstance(constructorArgs);
+ }
+ catch (Exception e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
+ public static Object convertToType(Object value, Class desiredClass)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ ExpressionFactory expFactory = FacesContext.getCurrentInstance().getApplication().getExpressionFactory();
+ return expFactory.coerceToType(value, desiredClass);
+ }
+ catch (Exception e)
+ {
+ String message = "Cannot coerce " + value.getClass().getName()
+ + " to " + desiredClass.getName();
+ log.log(Level.SEVERE, message, e);
+ throw new FacesException(message, e);
+ }
+ }
+
+ /**
+ * Gets the ClassLoader associated with the current thread. Returns the class loader associated with
+ * the specified default object if no context loader is associated with the current thread.
+ *
+ * @param defaultObject The default object to use to determine the class loader
+ * (if none associated with current thread.)
+ * @return ClassLoader
+ */
+ protected static ClassLoader getCurrentLoader(Object defaultObject)
+ {
+ ClassLoader loader = getContextClassLoader();
+ if(loader == null)
+ {
+ loader = defaultObject.getClass().getClassLoader();
+ }
+ return loader;
+ }
+
+ /**
+ * Gets the ClassLoader associated with the current thread. Includes a check for priviledges
+ * against java2 security to ensure no security related exceptions are encountered.
+ *
+ * @since 3.0.6
+ * @return ClassLoader
+ */
+ public static ClassLoader getContextClassLoader()
+ {
+ // call into the same method on ClassLoaderUtils. no need for duplicate code maintenance.
+ return ClassLoaderUtils.getContextClassLoader();
+ }
+
+ /**
+ * Creates ApplicationObjects like NavigationHandler or StateManager and creates
+ * the right wrapping chain of the ApplicationObjects known as the decorator pattern.
+ * @param <T>
+ * @param interfaceClass The class from which the implementation has to inherit from.
+ * @param classNamesIterator All the class names of the actual ApplicationObject implementations
+ * from the faces-config.xml.
+ * @param defaultObject The default implementation for the given ApplicationObject.
+ * @return
+ */
+ public static <T> T buildApplicationObject(Class<T> interfaceClass,
+ Collection<String> classNamesIterator, T defaultObject)
+ {
+ return buildApplicationObject(interfaceClass, null, null, classNamesIterator, defaultObject);
+ }
+
+ /**
+ * Creates ApplicationObjects like NavigationHandler or StateManager and creates
+ * the right wrapping chain of the ApplicationObjects known as the decorator pattern.
+ * @param <T>
+ * @param interfaceClass The class from which the implementation has to inherit from.
+ * @param extendedInterfaceClass A subclass of interfaceClass which specifies a more
+ * detailed implementation.
+ * @param extendedInterfaceWrapperClass A wrapper class for the case that you have an ApplicationObject
+ * which only implements the interfaceClass but not the
+ * extendedInterfaceClass.
+ * @param classNamesIterator All the class names of the actual ApplicationObject implementations
+ * from the faces-config.xml.
+ * @param defaultObject The default implementation for the given ApplicationObject.
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T buildApplicationObject(Class<T> interfaceClass, Class<? extends T> extendedInterfaceClass,
+ Class<? extends T> extendedInterfaceWrapperClass,
+ Collection<String> classNamesIterator, T defaultObject)
+ {
+ T current = defaultObject;
+
+
+ for (String implClassName : classNamesIterator)
+ {
+ Class<? extends T> implClass = ClassUtils.simpleClassForName(implClassName);
+
+ // check, if class is of expected interface type
+ if (!interfaceClass.isAssignableFrom(implClass))
+ {
+ throw new IllegalArgumentException("Class " + implClassName + " is no " + interfaceClass.getName());
+ }
+
+ if (current == null)
+ {
+ // nothing to decorate
+ current = (T) ClassUtils.newInstance(implClass);
+ }
+ else
+ {
+ // let's check if class supports the decorator pattern
+ T newCurrent = null;
+ try
+ {
+ Constructor<? extends T> delegationConstructor = null;
+
+ // first, if there is a extendedInterfaceClass,
+ // try to find a constructor that uses that
+ if (extendedInterfaceClass != null
+ && extendedInterfaceClass.isAssignableFrom(current.getClass()))
+ {
+ try
+ {
+ delegationConstructor =
+ implClass.getConstructor(new Class[] {extendedInterfaceClass});
+ }
+ catch (NoSuchMethodException mnfe)
+ {
+ // just eat it
+ }
+ }
+ if (delegationConstructor == null)
+ {
+ // try to find the constructor with the "normal" interfaceClass
+ delegationConstructor =
+ implClass.getConstructor(new Class[] {interfaceClass});
+ }
+ // impl class supports decorator pattern at this point
+ try
+ {
+ // create new decorator wrapping current
+ newCurrent = delegationConstructor.newInstance(new Object[] { current });
+ }
+ catch (InstantiationException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ catch (IllegalAccessException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ catch (InvocationTargetException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ }
+ catch (NoSuchMethodException e)
+ {
+ // no decorator pattern support
+ newCurrent = (T) ClassUtils.newInstance(implClass);
+ }
+
+ // now we have a new current object (newCurrent)
+ // --> find out if it is assignable from extendedInterfaceClass
+ // and if not, wrap it in a backwards compatible wrapper (if available)
+ if (extendedInterfaceWrapperClass != null
+ && !extendedInterfaceClass.isAssignableFrom(newCurrent.getClass()))
+ {
+ try
+ {
+ Constructor<? extends T> wrapperConstructor
+ = extendedInterfaceWrapperClass.getConstructor(
+ new Class[] {interfaceClass, extendedInterfaceClass});
+ newCurrent = wrapperConstructor.newInstance(new Object[] {newCurrent, current});
+ }
+ catch (NoSuchMethodException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ catch (InstantiationException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ catch (IllegalAccessException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ catch (InvocationTargetException e)
+ {
+ log.log(Level.SEVERE, e.getMessage(), e);
+ throw new FacesException(e);
+ }
+ }
+
+ current = newCurrent;
+ }
+ }
+
+ return current;
+ }
+}
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/MyFacesObjectInputStream.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/MyFacesObjectInputStream.java
new file mode 100644
index 0000000..4c30568
--- /dev/null
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/MyFacesObjectInputStream.java
@@ -0,0 +1,86 @@
+/*
+ * 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.trinidadinternal.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Proxy;
+
+/**
+ * Tried to deploy v0.4.2 on JBoss 3.2.1 and had a classloading problem again.
+ * The problem seemed to be with JspInfo, line 98. We are using an
+ * ObjectInputStream Class, which then cannot find the classes to deserialize
+ * the input stream. The solution appears to be to subclass ObjectInputStream
+ * (eg. CustomInputStream), and specify a different class-loading mechanism.
+ */
+public class MyFacesObjectInputStream
+ extends ObjectInputStream
+{
+ public MyFacesObjectInputStream(InputStream in) throws IOException
+ {
+ super(in);
+ }
+
+ protected Class resolveClass(ObjectStreamClass desc)
+ throws ClassNotFoundException, IOException
+ {
+ try
+ {
+ return ClassUtils.classForName(desc.getName());
+ }
+ catch (ClassNotFoundException e)
+ {
+ return super.resolveClass(desc);
+ }
+ }
+
+ protected Class resolveProxyClass(String[] interfaces)
+ throws IOException, ClassNotFoundException
+ {
+ // Only option that would match the current code would be to
+ // expand ClassLoaderExtension to handle 'getProxyClass', which
+ // would break all existing ClassLoaderExtension implementations
+ Class[] cinterfaces = new Class[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ cinterfaces[i] = ClassUtils.classForName(interfaces[i]);
+ }
+
+ try
+ {
+ // Try WebApp ClassLoader first
+ return Proxy.getProxyClass(ClassUtils.getContextClassLoader(), cinterfaces);
+ }
+ catch (Exception ex)
+ {
+ // fallback: Try ClassLoader for MyFacesObjectInputStream (i.e. the myfaces.jar lib)
+ try
+ {
+ return Proxy.getProxyClass(
+ MyFacesObjectInputStream.class.getClassLoader(), cinterfaces);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ClassNotFoundException(e.toString(), e);
+ }
+ }
+ }
+}
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/StateUtils.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/StateUtils.java
new file mode 100644
index 0000000..41ab582
--- /dev/null
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/StateUtils.java
@@ -0,0 +1,1072 @@
+/*
+ * 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.trinidadinternal.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.AccessController;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.faces.FacesException;
+import javax.faces.application.ViewExpiredException;
+import javax.faces.context.ExternalContext;
+import javax.servlet.ServletContext;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.myfaces.trinidadinternal.util.serial.DefaultSerialFactory;
+import org.apache.myfaces.trinidadinternal.util.serial.SerialFactory;
+
+/**
+ * <p>This Class exposes a handful of methods related to encryption,
+ * compression and serialization of the view state.</p>
+ *
+ * <ul>
+ * <li>ISO-8859-1 is the character set used.</li>
+ * <li>GZIP is used for all compression/decompression.</li>
+ * <li>Base64 is used for all encoding and decoding.</li>
+ * <li>DES is the default encryption algorithm</li>
+ * <li>ECB is the default mode</li>
+ * <li>PKCS5Padding is the default padding</li>
+ * <li>HmacSHA1 is the default MAC algorithm</li>
+ * <li>The default algorithm can be overridden using the
+ * <i>org.apache.myfaces.ALGORITHM</i> parameter</li>
+ * <li>The default mode and padding can be overridden using the
+ * <i>org.apache.myfaces.ALGORITHM.PARAMETERS</i> parameter</li>
+ * <li>This class has not been tested with modes other than ECB and CBC</li>
+ * <li>An initialization vector can be specified via the
+ * <i>org.apache.myfaces.ALGORITHM.IV</i> parameter</li>
+ * <li>The default MAC algorithm can be overridden using the
+ * <i>org.apache.myfaces.MAC_ALGORITHM</i> parameter</li>
+ * </ul>
+ *
+ * <p>The secret is interpretted as base 64 encoded. In other
+ * words, if your secret is "76543210", you would put "NzY1NDMyMTA=" in
+ * the deployment descriptor. This is needed so that key values are not
+ * limited to just values composed of printable characters.</p>
+ *
+ * <p>If you are using CBC mode encryption, you <b>must</b> specify an
+ * initialization vector.</p>
+ *
+ * <p>If you are using the AES algorithm and getting a SecurityException
+ * complaining about keysize, you most likely need to get the unlimited
+ * strength jurisdiction policy files from a place like
+ * http://java.sun.com/j2se/1.4.2/download.html .</p>
+ *
+ * @see org.apache.myfaces.webapp.StartupServletContextListener
+ */
+public final class StateUtils
+{
+
+ //private static final Log log = LogFactory.getLog(StateUtils.class);
+ private static final Logger log = Logger.getLogger(StateUtils.class.getName());
+
+ public static final String ZIP_CHARSET = "ISO-8859-1";
+
+ public static final String DEFAULT_ALGORITHM = "DES";
+ public static final String DEFAULT_ALGORITHM_PARAMS = "ECB/PKCS5Padding";
+
+ public static final String INIT_PREFIX = "org.apache.myfaces.";
+
+ /**
+ * Indicate if the view state is encrypted or not. By default, encryption is enabled.
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.USE_ENCRYPTION",since="1.1",
+ // defaultValue="true",expectedValues="true,false",group="state")
+ public static final String USE_ENCRYPTION = INIT_PREFIX + "USE_ENCRYPTION";
+
+ /**
+ * Defines the secret (Base64 encoded) used to initialize the secret key
+ * for encryption algorithm. See MyFaces wiki/web site documentation
+ * for instructions on how to configure an application for
+ * different encryption strengths.
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.SECRET",since="1.1",group="state")
+ public static final String INIT_SECRET = INIT_PREFIX + "SECRET";
+
+ /**
+ * Indicate the encryption algorithm used for encrypt the view state.
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM",since="1.1",
+ // defaultValue="DES",group="state",tags="performance")
+ public static final String INIT_ALGORITHM = INIT_PREFIX + "ALGORITHM";
+
+ /**
+ * If is set to "false", the secret key used for encryption algorithm is not cached. This is used
+ * when the returned SecretKey for encryption algorithm is not thread safe.
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.SECRET.CACHE",since="1.1",group="state")
+ public static final String INIT_SECRET_KEY_CACHE = INIT_SECRET + ".CACHE";
+
+ /**
+ * Defines the initialization vector (Base64 encoded) used for the encryption algorithm
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM.IV",since="1.1",group="state")
+ public static final String INIT_ALGORITHM_IV = INIT_ALGORITHM + ".IV";
+
+ /**
+ * Defines the default mode and padding used for the encryption algorithm
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.ALGORITHM.PARAMETERS",since="1.1",
+ // defaultValue="ECB/PKCS5Padding",group="state")
+ public static final String INIT_ALGORITHM_PARAM = INIT_ALGORITHM + ".PARAMETERS";
+
+ /**
+ * Defines the factory class name using for serialize/deserialize the view state returned
+ * by state manager into a byte array. The expected class must implement
+ * org.apache.myfaces.shared.util.serial.SerialFactory interface.
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.trinidad.SERIAL_FACTORY",
+ // since="1.1",group="state",tags="performance")
+ public static final String SERIAL_FACTORY = INIT_PREFIX + "trinidad.SERIAL_FACTORY";
+
+ /**
+ * Indicate if the view state should be compressed before encrypted(optional) and encoded
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.COMPRESS_STATE_IN_CLIENT",since="1.1",defaultValue="false",
+ // expectedValues="true,false",group="state",tags="performance")
+ public static final String COMPRESS_STATE_IN_CLIENT = INIT_PREFIX + "COMPRESS_STATE_IN_CLIENT";
+
+ public static final String DEFAULT_MAC_ALGORITHM = "HmacSHA1";
+
+ /**
+ * Indicate the algorithm used to calculate the Message Authentication Code that is
+ * added to the view state.
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.MAC_ALGORITHM",defaultValue="HmacSHA1",
+ // group="state",tags="performance")
+ public static final String INIT_MAC_ALGORITHM = "org.apache.myfaces.MAC_ALGORITHM";
+
+ /**
+ * Define the initialization code that are used to initialize the secret key used
+ * on the Message Authentication Code algorithm
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.MAC_SECRET",group="state")
+ public static final String INIT_MAC_SECRET = "org.apache.myfaces.MAC_SECRET";
+
+ /**
+ * If is set to "false", the secret key used for MAC algorithm is not cached. This is used
+ * when the returned SecretKey for mac algorithm is not thread safe.
+ */
+ //@JSFWebConfigParam(name="org.apache.myfaces.MAC_SECRET.CACHE",group="state")
+ public static final String INIT_MAC_SECRET_KEY_CACHE = "org.apache.myfaces.MAC_SECRET.CACHE";
+
+ /** Utility class, do not instatiate */
+ private StateUtils()
+ {
+ //nope
+ }
+
+ private static void testConfiguration(ExternalContext ctx)
+ {
+
+ String algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM);
+
+ if (algorithmParams == null)
+ {
+ algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM.toLowerCase());
+ }
+ String iv = ctx.getInitParameter(INIT_ALGORITHM_IV);
+
+ if (iv == null)
+ {
+ iv = ctx.getInitParameter(INIT_ALGORITHM_IV.toLowerCase());
+ }
+
+ if (algorithmParams != null && algorithmParams.startsWith("CBC") )
+ {
+ if(iv == null)
+ {
+ throw new FacesException(INIT_ALGORITHM_PARAM +
+ " parameter has been set with CBC mode," +
+ " but no initialization vector has been set " +
+ " with " + INIT_ALGORITHM_IV);
+ }
+ }
+
+ }
+
+ public static boolean enableCompression(ExternalContext ctx)
+ {
+ if(ctx == null)
+ {
+ throw new NullPointerException("ExternalContext ctx");
+ }
+
+ return "true".equals(ctx.getInitParameter(COMPRESS_STATE_IN_CLIENT));
+ }
+
+ public static boolean isSecure(ExternalContext ctx)
+ {
+
+ if(ctx == null)
+ {
+ throw new NullPointerException("ExternalContext ctx");
+ }
+
+ return ! "false".equals(ctx.getInitParameter(USE_ENCRYPTION));
+ }
+
+ /**
+ * This fires during the Render Response phase, saving state.
+ */
+
+ public static final String construct(Object object, ExternalContext ctx)
+ {
+ byte[] bytes = getAsByteArray(object, ctx);
+ if( enableCompression(ctx) )
+ {
+ bytes = compress(bytes);
+ }
+ if(isSecure(ctx))
+ {
+ bytes = encrypt(bytes, ctx);
+ }
+ bytes = encode(bytes);
+ try
+ {
+ return new String(bytes, ZIP_CHARSET);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
+ /**
+ * Performs serialization with the serialization provider created by the
+ * SerialFactory.
+ *
+ * @param object
+ * @param ctx
+ * @return
+ */
+
+ public static final byte[] getAsByteArray(Object object, ExternalContext ctx)
+ {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+ // get the Factory that was instantiated @ startup
+ SerialFactory serialFactory = (SerialFactory) ctx.getApplicationMap().get(SERIAL_FACTORY);
+
+ if(serialFactory == null)
+ {
+ // throw new NullPointerException("serialFactory");
+ serialFactory = new DefaultSerialFactory();
+ ctx.getApplicationMap().put(SERIAL_FACTORY, serialFactory);
+ }
+
+ try
+ {
+ ObjectOutputStream writer = serialFactory.getObjectOutputStream(outputStream);
+ writer.writeObject(object);
+ byte[] bytes = outputStream.toByteArray();
+ writer.close();
+ outputStream.close();
+ writer = null;
+ outputStream = null;
+ return bytes;
+ }
+ catch (IOException e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
+ public static byte[] encrypt(byte[] insecure, ExternalContext ctx)
+ {
+
+ if (ctx == null)
+ {
+ throw new NullPointerException("ExternalContext ctx");
+ }
+
+ testConfiguration(ctx);
+
+ SecretKey secretKey = (SecretKey) getSecret(ctx);
+ String algorithm = findAlgorithm(ctx);
+ String algorithmParams = findAlgorithmParams(ctx);
+ byte[] iv = findInitializationVector(ctx);
+
+ SecretKey macSecretKey = (SecretKey) getMacSecret(ctx);
+ String macAlgorithm = findMacAlgorithm(ctx);
+
+ try
+ {
+ // keep local to avoid threading issue
+ Mac mac = Mac.getInstance(macAlgorithm);
+ mac.init(macSecretKey);
+ Cipher cipher = Cipher.getInstance(algorithm + "/" + algorithmParams);
+ if (iv != null)
+ {
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
+ }
+ else
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+ }
+ if (log.isLoggable(Level.FINE))
+ {
+ log.fine("encrypting w/ " + algorithm + "/" + algorithmParams);
+ }
+
+ //EtM Composition Approach
+ int macLenght = mac.getMacLength();
+ byte[] secure = new byte[cipher.getOutputSize(insecure.length)+ macLenght];
+ int secureCount = cipher.doFinal(insecure,0,insecure.length,secure);
+ mac.update(secure, 0, secureCount);
+ mac.doFinal(secure, secureCount);
+
+ return secure;
+ }
+ catch (Exception e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
+ public static final byte[] compress(byte[] bytes)
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try
+ {
+ GZIPOutputStream gzip = new GZIPOutputStream(baos);
+ gzip.write(bytes, 0, bytes.length);
+ gzip.finish();
+ byte[] fewerBytes = baos.toByteArray();
+ gzip.close();
+ baos.close();
+ gzip = null;
+ baos = null;
+ return fewerBytes;
+ }
+ catch (IOException e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
+ public static final byte[] encode(byte[] bytes)
+ {
+ return new Base64().encode(bytes);
+ }
+
+ /**
+ * This fires during the Restore View phase, restoring state.
+ */
+ public static final Object reconstruct(String string, ExternalContext ctx)
+ {
+ byte[] bytes;
+ try
+ {
+ if(log.isLoggable(Level.FINE))
+ {
+ log.fine("Processing state : " + string);
+ }
+
+ bytes = string.getBytes(ZIP_CHARSET);
+ bytes = decode(bytes);
+ if(isSecure(ctx))
+ {
+ bytes = decrypt(bytes, ctx);
+ }
+ if( enableCompression(ctx) )
+ {
+ bytes = decompress(bytes);
+ }
+ return getAsObject(bytes, ctx);
+ }
+ catch (Throwable e)
+ {
+ if (log.isLoggable(Level.FINE))
+ {
+ log.log(Level.FINE, "View State cannot be reconstructed", e);
+ }
+ return null;
+ }
+ }
+
+ public static final byte[] decode(byte[] bytes)
+ {
+ return new Base64().decode(bytes);
+ }
+
+ public static final byte[] decompress(byte[] bytes)
+ {
+ if(bytes == null)
+ {
+ throw new NullPointerException("byte[] bytes");
+ }
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[bytes.length];
+ int length;
+
+ try
+ {
+ GZIPInputStream gis = new GZIPInputStream(bais);
+ while ((length = gis.read(buffer)) != -1)
+ {
+ baos.write(buffer, 0, length);
+ }
+
+ byte[] moreBytes = baos.toByteArray();
+ baos.close();
+ bais.close();
+ gis.close();
+ baos = null;
+ bais = null;
+ gis = null;
+ return moreBytes;
+ }
+ catch (IOException e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
+ public static byte[] decrypt(byte[] secure, ExternalContext ctx)
+ {
+ if (ctx == null)
+ {
+ throw new NullPointerException("ExternalContext ctx");
+ }
+
+ testConfiguration(ctx);
+
+ SecretKey secretKey = (SecretKey) getSecret(ctx);
+ String algorithm = findAlgorithm(ctx);
+ String algorithmParams = findAlgorithmParams(ctx);
+ byte[] iv = findInitializationVector(ctx);
+
+ SecretKey macSecretKey = (SecretKey) getMacSecret(ctx);
+ String macAlgorithm = findMacAlgorithm(ctx);
+
+ try
+ {
+ // keep local to avoid threading issue
+ Mac mac = Mac.getInstance(macAlgorithm);
+ mac.init(macSecretKey);
+ Cipher cipher = Cipher.getInstance(algorithm + "/"
+ + algorithmParams);
+ if (iv != null)
+ {
+ IvParameterSpec ivSpec = new IvParameterSpec(iv);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
+ }
+ else
+ {
+ cipher.init(Cipher.DECRYPT_MODE, secretKey);
+ }
+ if (log.isLoggable(Level.FINE))
+ {
+ log.fine("decrypting w/ " + algorithm + "/" + algorithmParams);
+ }
+
+ //EtM Composition Approach
+ int macLenght = mac.getMacLength();
+ mac.update(secure, 0, secure.length-macLenght);
+ byte[] signedDigestHash = mac.doFinal();
+
+ boolean isMacEqual = true;
+ for (int i = 0; i < signedDigestHash.length; i++)
+ {
+ if (signedDigestHash[i] != secure[secure.length-macLenght+i])
+ {
+ isMacEqual = false;
+ // MYFACES-2934 Must compare *ALL* bytes of the hash,
+ // otherwise a side-channel timing attack is theorically possible
+ // but with a very very low probability, because the
+ // comparison time is too small to be measured compared to
+ // the overall request time and in real life applications,
+ // there are too many uncertainties involved.
+ //break;
+ }
+ }
+ if (!isMacEqual)
+ {
+ throw new ViewExpiredException();
+ }
+
+ return cipher.doFinal(secure, 0, secure.length-macLenght);
+ }
+ catch (Exception e)
+ {
+ throw new FacesException(e);
+ }
+ }
+
+ /**
+ * Performs deserialization with the serialization provider created from the
+ * SerialFactory.
+ *
+ * @param bytes
+ * @param ctx
+ * @return
+ */
+
+ public static final Object getAsObject(byte[] bytes, ExternalContext ctx)
+ {
+ ByteArrayInputStream input = null;
+
+ try
+ {
+ input = new ByteArrayInputStream(bytes);
+
+ // get the Factory that was instantiated @ startup
+ SerialFactory serialFactory = (SerialFactory) ctx.getApplicationMap().get(SERIAL_FACTORY);
+
+ if(serialFactory == null)
+ {
+ throw new NullPointerException("serialFactory");
+ }
+
+ ObjectInputStream s = null;
+ Exception pendingException = null;
+ try
+ {
+ s = serialFactory.getObjectInputStream(input);
+ Object object = null;
+ if (System.getSecurityManager() != null)
+ {
+ final ObjectInputStream ois = s;
+ object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
+ {
+ //Put IOException and ClassNotFoundException as "checked" exceptions,
+ //so AccessController wrap them in a PrivilegedActionException
+ public Object run() throws PrivilegedActionException,
+ IOException, ClassNotFoundException
+ {
+ return ois.readObject();
+ }
+ });
+ // Since s has the same instance as ois,
+ // we don't need to close it here, rather
+ // close it on the finally block related to s
+ // and avoid duplicate close exceptions
+ // finally
+ // {
+ // ois.close();
+ // }
+ }
+ else
+ {
+ object = s.readObject();
+ }
+ return object;
+ }
+ catch (Exception e)
+ {
+ pendingException = e;
+ throw new FacesException(e);
+ }
+ finally
+ {
+ if (s != null)
+ {
+ try
+ {
+ s.close();
+ }
+ catch (IOException e)
+ {
+ // If a previous exception is thrown
+ // ignore this, but if not, wrap it in a
+ // FacesException and throw it. In this way
+ // we preserve the original semantic of this
+ // method, but we handle correctly the case
+ // when we close a stream. Obviously, the
+ // information about this exception is lost,
+ // but note that the interesting information
+ // is always on pendingException, since we
+ // only do a readObject() on the outer try block.
+ if (pendingException == null)
+ {
+ throw new FacesException(e);
+ }
+ }
+ finally
+ {
+ s = null;
+ }
+ }
+ }
+ }
+ finally
+ {
+ if (input != null)
+ {
+ try
+ {
+ input.close();
+ }
+ catch (IOException e)
+ {
+ //ignore it, because ByteArrayInputStream.close has
+ //no effect, but it is better to call close and preserve
+ //semantic from previous code.
+ }
+ finally
+ {
+ input = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Utility method for generating base 64 encoded strings.
+ *
+ * @param args
+ * @throws UnsupportedEncodingException
+ */
+ public static void main (String[] args) throws UnsupportedEncodingException
+ {
+ byte[] bytes = encode(args[0].getBytes(ZIP_CHARSET));
+ System.out.println(new String(bytes, ZIP_CHARSET));
+ }
+
+ private static byte[] findInitializationVector(ExternalContext ctx)
+ {
+
+ byte[] iv = null;
+ String ivString = ctx.getInitParameter(INIT_ALGORITHM_IV);
+
+ if(ivString == null)
+ {
+ ivString = ctx.getInitParameter(INIT_ALGORITHM_IV.toLowerCase());
+ }
+
+ if (ivString != null)
+ {
+ iv = new Base64().decode(ivString.getBytes());
+ }
+
+ return iv;
+ }
+
+ private static String findAlgorithmParams(ExternalContext ctx)
+ {
+
+ String algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM);
+
+ if (algorithmParams == null)
+ {
+ algorithmParams = ctx.getInitParameter(INIT_ALGORITHM_PARAM.toLowerCase());
+ }
+
+ if (algorithmParams == null)
+ {
+ algorithmParams = DEFAULT_ALGORITHM_PARAMS;
+ }
+
+ if (log.isLoggable(Level.FINE))
+ {
+ log.fine("Using algorithm paramaters " + algorithmParams);
+ }
+
+ return algorithmParams;
+ }
+
+ private static String findAlgorithm(ExternalContext ctx)
+ {
+
+ String algorithm = ctx.getInitParameter(INIT_ALGORITHM);
+
+ if (algorithm == null)
+ {
+ algorithm = ctx.getInitParameter(INIT_ALGORITHM.toLowerCase());
+ }
+
+ return findAlgorithm( algorithm );
+ }
+
+ private static String findAlgorithm(ServletContext ctx)
+ {
+
+ String algorithm = ctx.getInitParameter(INIT_ALGORITHM);
+
+ if (algorithm == null)
+ {
+ algorithm = ctx.getInitParameter(INIT_ALGORITHM.toLowerCase());
+ }
+
+ return findAlgorithm( algorithm );
+ }
+
+ private static String findAlgorithm(String initParam)
+ {
+
+ if (initParam == null)
+ {
+ initParam = DEFAULT_ALGORITHM;
+ }
+
+ if (log.isLoggable(Level.FINE))
+ {
+ log.fine("Using algorithm " + initParam);
+ }
+
+ return initParam;
+
+ }
+
+ /**
+ * Does nothing if the user has disabled the SecretKey cache. This is
+ * useful when dealing with a JCA provider whose SecretKey
+ * implementation is not thread safe.
+ *
+ * Instantiates a SecretKey instance based upon what the user has
+ * specified in the deployment descriptor. The SecretKey is then
+ * stored in application scope where it can be used for all requests.
+ */
+
+ public static void initSecret(ServletContext ctx)
+ {
+
+ if(ctx == null)
+ {
+ throw new NullPointerException("ServletContext ctx");
+ }
+
+ if (log.isLoggable(Level.FINE))
+ {
+ log.fine("Storing SecretKey @ " + INIT_SECRET_KEY_CACHE);
+ }
+
+ // Create and store SecretKey on application scope
+ String cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE);
+
+ if(cache == null)
+ {
+ cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE.toLowerCase());
+ }
+
+ if (!"false".equals(cache))
+ {
+ String algorithm = findAlgorithm(ctx);
+ // you want to create this as few times as possible
+ ctx.setAttribute(INIT_SECRET_KEY_CACHE, new SecretKeySpec(
+ findSecret(ctx, algorithm), algorithm));
+ }
+
+ if (log.isLoggable(Level.FINE))
+ {
+ log.fine("Storing SecretKey @ " + INIT_MAC_SECRET_KEY_CACHE);
+ }
+
+ String macCache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE);
+
+ if(macCache == null)
+ {
+ macCache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE.toLowerCase());
+ }
+
+ if (!"false".equals(macCache))
+ {
+ String macAlgorithm = findMacAlgorithm(ctx);
+ // init mac secret and algorithm
+ ctx.setAttribute(INIT_MAC_SECRET_KEY_CACHE, new SecretKeySpec(
+ findMacSecret(ctx, macAlgorithm), macAlgorithm));
+ }
+ }
+
+ private static SecretKey getSecret(ExternalContext ctx)
+ {
+ Object secretKey = (SecretKey) ctx.getApplicationMap().get(INIT_SECRET_KEY_CACHE);
+
+ if (secretKey == null)
+ {
+ String cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE);
+
+ if(cache == null)
+ {
+ cache = ctx.getInitParameter(INIT_SECRET_KEY_CACHE.toLowerCase());
+ }
+
+ if ("false".equals(cache))
+ {
+ // No cache is used. This option is activated
+ String secret = ctx.getInitParameter(INIT_SECRET);
+
+ if (secret == null)
+ {
+ secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
+ }
+
+ if (secret == null)
+ {
+ throw new NullPointerException("Could not find secret using key '" + INIT_SECRET + "'");
+ }
+
+ String algorithm = findAlgorithm(ctx);
+
+ secretKey = new SecretKeySpec(findSecret(ctx, algorithm), algorithm);
+ }
+ else
+ {
+ throw new NullPointerException("Could not find SecretKey in application scope using key '"
+ + INIT_SECRET_KEY_CACHE + "'");
+ }
+ }
+
+ if( ! ( secretKey instanceof SecretKey ) )
+ {
+ throw new ClassCastException("Did not find an instance of SecretKey "
+ + "in application scope using the key '" + INIT_SECRET_KEY_CACHE + "'");
+ }
+
+
+ return (SecretKey) secretKey;
+ }
+
+ private static byte[] findSecret(ExternalContext ctx, String algorithm)
+ {
+ String secret = ctx.getInitParameter(INIT_SECRET);
+
+ if (secret == null)
+ {
+ secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
+ }
+
+ return findSecret(secret, algorithm);
+ }
+
+ private static byte[] findSecret(ServletContext ctx, String algorithm)
+ {
+ String secret = ctx.getInitParameter(INIT_SECRET);
+
+ if (secret == null)
+ {
+ secret = ctx.getInitParameter(INIT_SECRET.toLowerCase());
+ }
+
+ return findSecret(secret, algorithm);
+ }
+
+ private static byte[] findSecret(String secret, String algorithm)
+ {
+ byte[] bytes = null;
+
+ if(secret == null)
+ {
+ try
+ {
+ KeyGenerator kg = KeyGenerator.getInstance(algorithm);
+ bytes = kg.generateKey().getEncoded();
+
+ if(log.isLoggable(Level.FINE))
+ {
+ log.fine("generated random password of length " + bytes.length);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Generate random password length 8,
+ int length = 8;
+ bytes = new byte[length];
+ new Random().nextBytes(bytes);
+
+ if(log.isLoggable(Level.FINE))
+ {
+ log.fine("generated random password of length " + length);
+ }
+ }
+ }
+ else
+ {
+ bytes = new Base64().decode(secret.getBytes());
+ }
+
+ return bytes;
+ }
+
+ private static String findMacAlgorithm(ExternalContext ctx)
+ {
+
+ String algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM);
+
+ if (algorithm == null)
+ {
+ algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM.toLowerCase());
+ }
+
+ return findMacAlgorithm( algorithm );
+
+ }
+
+ private static String findMacAlgorithm(ServletContext ctx)
+ {
+
+ String algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM);
+
+ if (algorithm == null)
+ {
+ algorithm = ctx.getInitParameter(INIT_MAC_ALGORITHM.toLowerCase());
+ }
+
+ return findMacAlgorithm( algorithm );
+
+ }
+
+ private static String findMacAlgorithm(String initParam)
+ {
+
+ if (initParam == null)
+ {
+ initParam = DEFAULT_MAC_ALGORITHM;
+ }
+
+ if (log.isLoggable(Level.FINE))
+ {
+ log.fine("Using algorithm " + initParam);
+ }
+
+ return initParam;
+
+ }
+
+ private static SecretKey getMacSecret(ExternalContext ctx)
+ {
+ Object secretKey = (SecretKey) ctx.getApplicationMap().get(INIT_MAC_SECRET_KEY_CACHE);
+
+ if (secretKey == null)
+ {
+ String cache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE);
+
+ if(cache == null)
+ {
+ cache = ctx.getInitParameter(INIT_MAC_SECRET_KEY_CACHE.toLowerCase());
+ }
+
+ if ("false".equals(cache))
+ {
+ // No cache is used. This option is activated
+ String secret = ctx.getInitParameter(INIT_MAC_SECRET);
+
+ if (secret == null)
+ {
+ secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
+ }
+
+ if (secret == null)
+ {
+ throw new NullPointerException("Could not find secret using key '" + INIT_MAC_SECRET + "'");
+ }
+
+ String macAlgorithm = findMacAlgorithm(ctx);
+
+ secretKey = new SecretKeySpec(findMacSecret(ctx, macAlgorithm), macAlgorithm);
+ }
+ else
+ {
+ throw new NullPointerException("Could not find SecretKey in application scope using key '"
+ + INIT_MAC_SECRET_KEY_CACHE + "'");
+ }
+ }
+
+ if( ! ( secretKey instanceof SecretKey ) )
+ {
+ throw new ClassCastException("Did not find an instance of SecretKey "
+ + "in application scope using the key '" + INIT_MAC_SECRET_KEY_CACHE + "'");
+ }
+
+
+ return (SecretKey) secretKey;
+ }
+
+ private static byte[] findMacSecret(ExternalContext ctx, String algorithm)
+ {
+ String secret = ctx.getInitParameter(INIT_MAC_SECRET);
+
+ if (secret == null)
+ {
+ secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
+ }
+
+ return findMacSecret(secret, algorithm);
+ }
+
+ private static byte[] findMacSecret(ServletContext ctx, String algorithm)
+ {
+ String secret = ctx.getInitParameter(INIT_MAC_SECRET);
+
+ if (secret == null)
+ {
+ secret = ctx.getInitParameter(INIT_MAC_SECRET.toLowerCase());
+ }
+
+ return findMacSecret(secret, algorithm);
+ }
+
+ private static byte[] findMacSecret(String secret, String algorithm)
+ {
+ byte[] bytes = null;
+
+ if(secret == null)
+ {
+ try
+ {
+ KeyGenerator kg = KeyGenerator.getInstance(algorithm);
+ bytes = kg.generateKey().getEncoded();
+
+ if(log.isLoggable(Level.FINE))
+ {
+ log.fine("generated random mac password of length " + bytes.length);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // Generate random password length 8,
+ int length = 8;
+ bytes = new byte[length];
+ new Random().nextBytes(bytes);
+
+ if(log.isLoggable(Level.FINE))
+ {
+ log.fine("generated random mac password of length " + length);
+ }
+ }
+ }
+ else
+ {
+ bytes = new Base64().decode(secret.getBytes());
+ }
+
+ return bytes;
+ }
+}
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/serial/DefaultSerialFactory.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/serial/DefaultSerialFactory.java
new file mode 100644
index 0000000..efaa810
--- /dev/null
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/serial/DefaultSerialFactory.java
@@ -0,0 +1,42 @@
+/*
+ * 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.trinidadinternal.util.serial;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+
+import org.apache.myfaces.trinidadinternal.util.MyFacesObjectInputStream;
+
+public class DefaultSerialFactory implements SerialFactory
+{
+
+ public ObjectOutputStream getObjectOutputStream(OutputStream outputStream) throws IOException
+ {
+ return new ObjectOutputStream(outputStream);
+ }
+
+ public ObjectInputStream getObjectInputStream(InputStream inputStream) throws IOException
+ {
+ return new MyFacesObjectInputStream(inputStream);
+ }
+
+}
diff --git a/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/serial/SerialFactory.java b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/serial/SerialFactory.java
new file mode 100644
index 0000000..76487fb
--- /dev/null
+++ b/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/util/serial/SerialFactory.java
@@ -0,0 +1,31 @@
+/*
+ * 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.trinidadinternal.util.serial;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+
+public interface SerialFactory
+{
+ ObjectOutputStream getObjectOutputStream(OutputStream outputStream) throws IOException;
+ ObjectInputStream getObjectInputStream(InputStream inputStream) throws IOException;
+}
diff --git a/trinidad-impl/src/main/xrts/org/apache/myfaces/trinidadinternal/renderkit/core/resource/CoreBundle_cs.xrts b/trinidad-impl/src/main/xrts/org/apache/myfaces/trinidadinternal/renderkit/core/resource/CoreBundle_cs.xrts
index ef02939..e98043f 100644
--- a/trinidad-impl/src/main/xrts/org/apache/myfaces/trinidadinternal/renderkit/core/resource/CoreBundle_cs.xrts
+++ b/trinidad-impl/src/main/xrts/org/apache/myfaces/trinidadinternal/renderkit/core/resource/CoreBundle_cs.xrts
@@ -105,9 +105,9 @@
<resource key="af_table.SELECT_RANGE_NEXT" dnt="false">Následující {0}</resource>
<!--navigation bar with no more records going forward.-->
<!--the following text will be drawn in a disabled font-->
-<resource key="af_selectRangeChoiceBar.DISABLED_NEXT" dnt="false">Další</resource>
-<resource key="af_table.SELECT_RANGE_DISABLED_NEXT" dnt="false">Další</resource>
-<resource key="af_treeTable.DISABLED_NEXT" dnt="false">Další</resource>
+<resource key="af_selectRangeChoiceBar.DISABLED_NEXT" dnt="false">Následující</resource>
+<resource key="af_table.SELECT_RANGE_DISABLED_NEXT" dnt="false">Následující</resource>
+<resource key="af_treeTable.DISABLED_NEXT" dnt="false">Následující</resource>
<!--navigation bar with no more records going backward.-->
<!--the following text will be drawn in a disabled font-->
<resource key="af_selectRangeChoiceBar.DISABLED_PREVIOUS" dnt="false">PĹ™edchozí</resource>