You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by de...@apache.org on 2018/05/03 18:25:49 UTC
[myfaces-test] 02/21: copy shale test to myfaces
This is an automated email from the ASF dual-hosted git repository.
deki pushed a commit to branch 1_0_0_alpha
in repository https://gitbox.apache.org/repos/asf/myfaces-test.git
commit 2c106d1ab42f028706c511011559bfaca1d15098
Author: Matthias Wessendorf <ma...@apache.org>
AuthorDate: Thu May 21 20:41:48 2009 +0000
copy shale test to myfaces
---
shale-test/pom.xml | 219 +++++
.../shale/test/base/AbstractJsfTestCase.java | 198 +++++
.../test/base/AbstractViewControllerTestCase.java | 97 +++
.../apache/shale/test/cargo/CargoTestSetup.java | 174 ++++
.../org/apache/shale/test/config/ConfigParser.java | 480 +++++++++++
.../java/org/apache/shale/test/config/package.html | 30 +
.../apache/shale/test/el/AbstractELResolver.java | 71 ++
.../test/el/FacesImplicitObjectELResolver.java | 272 +++++++
.../test/el/FacesPropertyResolverChainWrapper.java | 233 ++++++
.../test/el/FacesResourceBundleELResolver.java | 212 +++++
.../test/el/FacesScopedAttributeELResolver.java | 241 ++++++
.../test/el/FacesVariableResolverChainWrapper.java | 162 ++++
.../org/apache/shale/test/el/MockELContext.java | 124 +++
.../shale/test/el/MockExpressionFactory.java | 257 ++++++
.../apache/shale/test/el/MockFunctionMapper.java | 77 ++
.../apache/shale/test/el/MockMethodExpression.java | 237 ++++++
.../apache/shale/test/el/MockValueExpression.java | 306 +++++++
.../apache/shale/test/el/MockVariableMapper.java | 79 ++
.../shale/test/el/MockVariableValueExpression.java | 208 +++++
.../java/org/apache/shale/test/el/package.html | 21 +
.../test/htmlunit/AbstractHtmlUnitTestCase.java | 330 ++++++++
.../shale/test/jmock/AbstractJmockJsfTestCase.java | 188 +++++
.../apache/shale/test/mock/MockActionListener.java | 65 ++
.../apache/shale/test/mock/MockApplication.java | 463 +++++++++++
.../apache/shale/test/mock/MockApplication12.java | 274 +++++++
.../shale/test/mock/MockApplicationFactory.java | 103 +++
.../apache/shale/test/mock/MockApplicationMap.java | 248 ++++++
.../apache/shale/test/mock/MockEnumeration.java | 79 ++
.../shale/test/mock/MockExternalContext.java | 476 +++++++++++
.../shale/test/mock/MockExternalContext12.java | 120 +++
.../apache/shale/test/mock/MockFacesContext.java | 324 ++++++++
.../apache/shale/test/mock/MockFacesContext12.java | 114 +++
.../shale/test/mock/MockFacesContextFactory.java | 175 ++++
.../shale/test/mock/MockHttpServletRequest.java | 894 +++++++++++++++++++++
.../shale/test/mock/MockHttpServletResponse.java | 454 +++++++++++
.../apache/shale/test/mock/MockHttpSession.java | 338 ++++++++
.../apache/shale/test/mock/MockMethodBinding.java | 249 ++++++
.../shale/test/mock/MockNavigationHandler.java | 110 +++
.../apache/shale/test/mock/MockPortletContext.java | 326 ++++++++
.../apache/shale/test/mock/MockPortletRequest.java | 421 ++++++++++
.../shale/test/mock/MockPortletResponse.java | 62 ++
.../apache/shale/test/mock/MockPortletSession.java | 268 ++++++
.../org/apache/shale/test/mock/MockPrincipal.java | 80 ++
.../apache/shale/test/mock/MockPrintWriter.java | 88 ++
.../shale/test/mock/MockPropertyResolver.java | 218 +++++
.../org/apache/shale/test/mock/MockRenderKit.java | 139 ++++
.../shale/test/mock/MockRenderKitFactory.java | 114 +++
.../org/apache/shale/test/mock/MockRequestMap.java | 253 ++++++
.../apache/shale/test/mock/MockResponseWriter.java | 371 +++++++++
.../org/apache/shale/test/mock/MockServlet.java | 122 +++
.../apache/shale/test/mock/MockServletConfig.java | 126 +++
.../apache/shale/test/mock/MockServletContext.java | 479 +++++++++++
.../shale/test/mock/MockServletOutputStream.java | 96 +++
.../org/apache/shale/test/mock/MockSessionMap.java | 254 ++++++
.../apache/shale/test/mock/MockStateManager.java | 113 +++
.../apache/shale/test/mock/MockValueBinding.java | 373 +++++++++
.../shale/test/mock/MockVariableResolver.java | 133 +++
.../apache/shale/test/mock/MockViewHandler.java | 152 ++++
.../mock/lifecycle/ApplyRequestValuesExecutor.java | 38 +
.../mock/lifecycle/DefaultRestoreViewSupport.java | 114 +++
.../mock/lifecycle/InvokeApplicationExecutor.java | 38 +
.../shale/test/mock/lifecycle/MockLifecycle.java | 174 ++++
.../test/mock/lifecycle/MockLifecycleFactory.java | 89 ++
.../shale/test/mock/lifecycle/PhaseExecutor.java | 48 ++
.../test/mock/lifecycle/PhaseListenerManager.java | 100 +++
.../mock/lifecycle/ProcessValidationsExecutor.java | 38 +
.../mock/lifecycle/RenderResponseExecutor.java | 50 ++
.../test/mock/lifecycle/RestoreViewExecutor.java | 168 ++++
.../test/mock/lifecycle/RestoreViewSupport.java | 72 ++
.../mock/lifecycle/UpdateModelValuesExecutor.java | 39 +
shale-test/src/main/resources/META-INF/LICENSE.txt | 202 +++++
shale-test/src/main/resources/META-INF/NOTICE.txt | 9 +
shale-test/src/site/site.xml | 83 ++
shale-test/src/site/xdoc/index.xml | 286 +++++++
.../shale/test/config/ConfigParserTestCase.java | 158 ++++
.../org/apache/shale/test/config/MyConverter.java | 37 +
.../org/apache/shale/test/config/MyRenderer.java | 27 +
.../test/el/MockExpressionFactoryTestCase.java | 344 ++++++++
.../shale/test/mock/MockObjectsTestCase.java | 249 ++++++
.../org/apache/shale/test/mock/TestMockBean.java | 60 ++
.../apache/shale/test/mock/ValueBindingTest.java | 80 ++
.../java/org/apache/shale/test/mock/data/Bean.java | 44 +
.../apache/shale/test/config/faces-config-1.xml | 73 ++
83 files changed, 15510 insertions(+)
diff --git a/shale-test/pom.xml b/shale-test/pom.xml
new file mode 100644
index 0000000..89a98be
--- /dev/null
+++ b/shale-test/pom.xml
@@ -0,0 +1,219 @@
+<!--
+/*
+ * 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.
+ *
+ * $Id$
+ */
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.shale</groupId>
+ <artifactId>shale-parent</artifactId>
+ <version>1.1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>shale-test</artifactId>
+ <packaging>jar</packaging>
+ <name>Shale Test Framework</name>
+
+ <dependencies>
+
+ <!-- Required only for using the org.apache.shale.test.config package -->
+ <dependency>
+ <groupId>commons-digester</groupId>
+ <artifactId>commons-digester</artifactId>
+ <version>1.8</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>htmlunit</groupId>
+ <artifactId>htmlunit</artifactId>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>jmock</groupId>
+ <artifactId>jmock</artifactId>
+ <version>1.0.1</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>jmock</groupId>
+ <artifactId>jmock-cglib</artifactId>
+ <version>1.0.1</version>
+ <optional>true</optional>
+ </dependency>
+
+ <!-- For the "org.apache.shale.test.cargo" package, we need to have -->
+ <!-- JUnit as a compile time dependency, not just scope="test". -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.cargo</groupId>
+ <artifactId>cargo-core-uberjar</artifactId>
+ <version>0.8</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.cargo</groupId>
+ <artifactId>cargo-ant</artifactId>
+ <version>0.8</version>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.portlet</groupId>
+ <artifactId>portlet-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+ <!-- Allow building with JDK 1.4 as well as JDK 1.5,
+ the 1.4 profile caters only to JSF 1.1 -->
+ <profiles>
+
+ <profile>
+ <id>shale-test-jdk14</id>
+ <activation>
+ <jdk>1.4</jdk>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-api</artifactId>
+ <version>1.1.4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.myfaces.core</groupId>
+ <artifactId>myfaces-impl</artifactId>
+ <version>1.1.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jsp-api</artifactId>
+ <version>2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>org/apache/shale/test/el/**</exclude>
+ <exclude>org/apache/shale/test/mock/*12.java</exclude>
+ </excludes>
+ <testExcludes>
+ <testExclude>org/apache/shale/test/el/**</testExclude>
+ </testExcludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>shale-test-jdk15</id>
+ <activation>
+ <jdk>1.5</jdk>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>1.2_03</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>1.2_03</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet.jsp</groupId>
+ <artifactId>jsp-api</artifactId>
+ <version>2.1</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>shale-test-jdk16</id>
+ <activation>
+ <jdk>1.6</jdk>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>1.2_03</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>1.2_03</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet.jsp</groupId>
+ <artifactId>jsp-api</artifactId>
+ <version>2.1</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ </profiles>
+
+</project>
diff --git a/shale-test/src/main/java/org/apache/shale/test/base/AbstractJsfTestCase.java b/shale-test/src/main/java/org/apache/shale/test/base/AbstractJsfTestCase.java
new file mode 100644
index 0000000..8f45cc7
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/base/AbstractJsfTestCase.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.test.base;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.component.UIViewRoot;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKitFactory;
+
+import junit.framework.TestCase;
+
+import org.apache.shale.test.mock.MockApplication;
+import org.apache.shale.test.mock.MockExternalContext;
+import org.apache.shale.test.mock.MockFacesContext;
+import org.apache.shale.test.mock.MockFacesContextFactory;
+import org.apache.shale.test.mock.MockHttpServletRequest;
+import org.apache.shale.test.mock.MockHttpServletResponse;
+import org.apache.shale.test.mock.MockHttpSession;
+import org.apache.shale.test.mock.MockRenderKit;
+import org.apache.shale.test.mock.MockServletConfig;
+import org.apache.shale.test.mock.MockServletContext;
+import org.apache.shale.test.mock.lifecycle.MockLifecycle;
+import org.apache.shale.test.mock.lifecycle.MockLifecycleFactory;
+
+/**
+ * <p>Abstract JUnit test case base class, which sets up the JavaServer Faces
+ * mock object environment for a particular simulated request. The following
+ * protected variables are initialized in the <code>setUp()</code> method, and
+ * cleaned up in the <code>tearDown()</code> method:</p>
+ * <ul>
+ * <li><code>application</code> (<code>MockApplication</code>)</li>
+ * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+ * <li><code>externalContext</code> (<code>MockExternalContext</code>)</li>
+ * <li><code>facesContext</code> (<code>MockFacesContext</code>)</li>
+ * <li><code>lifecycle</code> (<code>MockLifecycle</code>)</li>
+ * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+ * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+ * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+ * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+ * </ul>
+ *
+ * <p>In addition, appropriate factory classes will have been registered with
+ * <code>javax.faces.FactoryFinder</code> for <code>Application</code> and
+ * <code>RenderKit</code> instances. The created <code>FacesContext</code>
+ * instance will also have been registered in the apppriate thread local
+ * variable, to simulate what a servlet container would do.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ */
+
+public abstract class AbstractJsfTestCase extends TestCase {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a new instance of this test case.</p>
+ *
+ * @param name Name of this test case
+ */
+ public AbstractJsfTestCase(String name) {
+ super(name);
+ }
+
+
+ // ---------------------------------------------------- Overall Test Methods
+
+
+ /**
+ * <p>Set up instance variables required by this test case.</p>
+ */
+ protected void setUp() throws Exception {
+
+ // Set up a new thread context class loader
+ threadContextClassLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(new URLClassLoader(new URL[0],
+ this.getClass().getClassLoader()));
+
+ // Set up Servlet API Objects
+ servletContext = new MockServletContext();
+ config = new MockServletConfig(servletContext);
+ session = new MockHttpSession();
+ session.setServletContext(servletContext);
+ request = new MockHttpServletRequest(session);
+ request.setServletContext(servletContext);
+ response = new MockHttpServletResponse();
+
+ // Set up JSF API Objects
+ FactoryFinder.releaseFactories();
+ FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
+ "org.apache.shale.test.mock.MockApplicationFactory");
+ FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
+ "org.apache.shale.test.mock.MockFacesContextFactory");
+ FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY,
+ "org.apache.shale.test.mock.lifecycle.MockLifecycleFactory");
+ FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
+ "org.apache.shale.test.mock.MockRenderKitFactory");
+
+ externalContext =
+ new MockExternalContext(servletContext, request, response);
+ lifecycleFactory = (MockLifecycleFactory)
+ FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+ lifecycle = (MockLifecycle)
+ lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+ facesContextFactory = (MockFacesContextFactory)
+ FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+ facesContext = (MockFacesContext)
+ facesContextFactory.getFacesContext(servletContext,
+ request,
+ response,
+ lifecycle);
+ externalContext = (MockExternalContext) facesContext.getExternalContext();
+ UIViewRoot root = new UIViewRoot();
+ root.setViewId("/viewId");
+ root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+ facesContext.setViewRoot(root);
+ ApplicationFactory applicationFactory = (ApplicationFactory)
+ FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
+ application = (MockApplication) applicationFactory.getApplication();
+ facesContext.setApplication(application);
+ RenderKitFactory renderKitFactory = (RenderKitFactory)
+ FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ renderKit = new MockRenderKit();
+ renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT, renderKit);
+
+ }
+
+
+ /**
+ * <p>Tear down instance variables required by this test case.</p>
+ */
+ protected void tearDown() throws Exception {
+
+ application = null;
+ config = null;
+ externalContext = null;
+ facesContext.release();
+ facesContext = null;
+ lifecycle = null;
+ lifecycleFactory = null;
+ renderKit = null;
+ request = null;
+ response = null;
+ servletContext = null;
+ session = null;
+ FactoryFinder.releaseFactories();
+
+ Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+ threadContextClassLoader = null;
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ // Mock object instances for our tests
+ protected MockApplication application = null;
+ protected MockServletConfig config = null;
+ protected MockExternalContext externalContext = null;
+ protected MockFacesContext facesContext = null;
+ protected MockFacesContextFactory facesContextFactory = null;
+ protected MockLifecycle lifecycle = null;
+ protected MockLifecycleFactory lifecycleFactory = null;
+ protected MockRenderKit renderKit = null;
+ protected MockHttpServletRequest request = null;
+ protected MockHttpServletResponse response = null;
+ protected MockServletContext servletContext = null;
+ protected MockHttpSession session = null;
+
+ // Thread context class loader saved and restored after each test
+ private ClassLoader threadContextClassLoader = null;
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/base/AbstractViewControllerTestCase.java b/shale-test/src/main/java/org/apache/shale/test/base/AbstractViewControllerTestCase.java
new file mode 100644
index 0000000..57a93d6
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/base/AbstractViewControllerTestCase.java
@@ -0,0 +1,97 @@
+/*
+ * 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.shale.test.base;
+
+import java.util.Iterator;
+
+/**
+ * <p>Abstract base class for testing <code>ViewController</code>
+ * implementations.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ */
+public abstract class AbstractViewControllerTestCase extends AbstractJsfTestCase {
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a new instance of this test case.</p>
+ *
+ * @param name Test case name
+ */
+ public AbstractViewControllerTestCase(String name) {
+ super(name);
+ }
+
+
+ // ---------------------------------------------------- Overall Test Methods
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ // ------------------------------------------------------- Protected Methods
+
+
+ /**
+ * <p>Test that the specified number of messages have been queued on the
+ * <code>FacesContext</code> instance, without regard to matching a
+ * particular client identifier.</p>
+ *
+ * @param expected The expected number of messages
+ */
+ protected void checkMessageCount(int expected) {
+
+ int actual = 0;
+ Iterator messages = facesContext.getMessages();
+ while (messages.hasNext()) {
+ messages.next();
+ actual++;
+ }
+ assertEquals("Complete message count", expected, actual);
+
+ }
+
+
+ /**
+ * <p>Test that the specified number of messages have been queued on the
+ * <code>FacesContext</code> instance, for the specified client id.</p>
+ *
+ * @param clientId Client identifier of the component for which to
+ * count queued messages
+ * @param expected The expected number of messages
+ */
+ protected void checkMessageCount(String clientId, int expected) {
+
+ int actual = 0;
+ Iterator messages = facesContext.getMessages(clientId);
+ while (messages.hasNext()) {
+ messages.next();
+ actual++;
+ }
+ assertEquals("Complete message count", expected, actual);
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/cargo/CargoTestSetup.java b/shale-test/src/main/java/org/apache/shale/test/cargo/CargoTestSetup.java
new file mode 100644
index 0000000..42d42b9
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/cargo/CargoTestSetup.java
@@ -0,0 +1,174 @@
+/*
+ * 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.shale.test.cargo;
+
+import java.io.File;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+
+import org.codehaus.cargo.container.InstalledLocalContainer;
+import org.codehaus.cargo.container.ContainerType;
+import org.codehaus.cargo.container.tomcat.Tomcat5xInstalledLocalContainer;
+import org.codehaus.cargo.container.deployable.Deployable;
+import org.codehaus.cargo.container.deployable.DeployableType;
+import org.codehaus.cargo.container.configuration.LocalConfiguration;
+import org.codehaus.cargo.container.configuration.ConfigurationType;
+import org.codehaus.cargo.generic.deployable.DefaultDeployableFactory;
+import org.codehaus.cargo.generic.configuration.ConfigurationFactory;
+import org.codehaus.cargo.generic.configuration.DefaultConfigurationFactory;
+import org.codehaus.cargo.generic.DefaultContainerFactory;
+import org.codehaus.cargo.util.log.FileLogger;
+
+/**
+ * <p>Convenience <code>TestSetup</code> class which uses Cargo to start
+ * and stop a Servlet container.</p>
+ */
+public class CargoTestSetup extends TestSetup {
+
+ // ------------------------------------------------------------ Constructors
+
+ /**
+ * <p>Construct a new instance of this test setup.</p>
+ *
+ * @param test Tests to be run within this test setup.
+ */
+ public CargoTestSetup(Test test) {
+ super(test);
+ }
+
+ // ------------------------------------------------------ Instance Variables
+
+ /**
+ * <p>The installed local container for this test setup.</p>
+ */
+ private InstalledLocalContainer container;
+
+ // ------------------------------------------------------ Test Setup Methods
+
+ /**
+ * <p>Start the container prior to running the tests.</p>
+ * <p>The following System properties are used:
+ * <ul>
+ * <li>cargo.container.id - ID of the container to use. [tomcat5x]</li>
+ * <li>cargo.container.home - Full path to a local installation of the container.
+ * If not set, uses the value of the TOMCAT_HOME environment variable.
+ * One of cargo.container.home or TOMCAT_HOME is REQUIRED.</li>
+ * <li>cargo.deployable - Full path to the war file to deploy. REQUIRED.</li>
+ * <li>cargo.container.output - Full path to a file to use for output. [none]</li>
+ * <li>cargo.container.log - Full path to a file to use for logging. [none]</li>
+ * <li>cargo.servlet.port - The port on which the container should listen. [8080]</li>
+ * </ul>
+ * </p>
+ *
+ * @throws Exception if an error occurs.
+ */
+ protected void setUp() throws Exception {
+
+ super.setUp();
+
+ // If there is no container id, default to Tomcat 5x
+ String containerId = System.getProperty("cargo.container.id");
+ if (containerId == null) {
+ containerId = Tomcat5xInstalledLocalContainer.ID;
+ }
+ System.out.println("[INFO] container id: " + containerId);
+
+ // Construct the war, using the container id and the path to the war file
+ String deployablePath = System.getProperty("cargo.deployable");
+ System.out.println("[INFO] deployable: " + deployablePath);
+ Deployable war = new DefaultDeployableFactory().createDeployable(
+ containerId,
+ deployablePath,
+ DeployableType.WAR);
+
+ // Container configuration
+ ConfigurationFactory configurationFactory =
+ new DefaultConfigurationFactory();
+
+ LocalConfiguration configuration =
+ (LocalConfiguration) configurationFactory.createConfiguration(
+ containerId,
+ ConfigurationType.STANDALONE);
+
+ // Find and (if provided) set the port to use for the container.
+ String servletPort = System.getProperty("cargo.servlet.port");
+ if (servletPort != null) {
+ configuration.setProperty("cargo.servlet.port", servletPort);
+ System.out.println("[INFO] servlet port: " + servletPort);
+ }
+
+ configuration.addDeployable(war);
+
+ container = (InstalledLocalContainer)
+ new DefaultContainerFactory().createContainer(
+ containerId,
+ ContainerType.INSTALLED, configuration);
+
+ // If 'cargo.container.home' is not set, or if an expression was
+ // passed through, try to use the TOMCAT_HOME environment variable.
+ String containerHome = System.getProperty("cargo.container.home");
+ if (containerHome == null || containerHome.startsWith("$")) {
+ containerHome = System.getenv("TOMCAT_HOME");
+ }
+ System.out.println("[INFO] container home: " + containerHome);
+ container.setHome(new File(containerHome));
+
+ // Find and (if provided) set the path to a log file
+ String containerLog = System.getProperty("cargo.container.log");
+ if (containerLog != null) {
+ System.out.println("[INFO] container log: " + containerLog);
+ container.setLogger(new FileLogger(containerLog, false));
+ }
+
+ // Find and (if provided) set the path to an output file
+ String containerOutput = System.getProperty("cargo.container.output");
+ if (containerOutput != null) {
+ System.out.println("[INFO] container output: " + containerOutput);
+ container.setOutput(new File(containerOutput));
+ }
+
+ container.start();
+ }
+
+
+ /**
+ * Stop the container after running the tests.
+ *
+ * @throws Exception if an error occurs.
+ */
+ protected void tearDown() throws Exception {
+ container.stop();
+ super.tearDown();
+ }
+
+
+ /**
+ * Return the name of the test setup.
+ * (Temporarily required due to MSUREFIRE-119.)
+ *
+ * @return the name of the test setup.
+ * @deprecated No replacement.
+ */
+
+ public String getName() {
+ return "CargoTestSetup";
+ }
+
+}
+
diff --git a/shale-test/src/main/java/org/apache/shale/test/config/ConfigParser.java b/shale-test/src/main/java/org/apache/shale/test/config/ConfigParser.java
new file mode 100644
index 0000000..b8e0dc4
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/config/ConfigParser.java
@@ -0,0 +1,480 @@
+/*
+ * 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.shale.test.config;
+
+import java.io.IOException;
+import java.net.URL;
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.render.Renderer;
+import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.Rule;
+import org.apache.shale.test.mock.MockRenderKit;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * <p>Utility class to parse JavaServer Faces configuration resources, and
+ * register JSF artifacts with the mock object hierarchy.</p>
+ *
+ * <p>The following artifacts are registered:</p>
+ * <ul>
+ * <li><code>Converter</code> (by-id and by-class)</li>
+ * <li><code>RenderKit</code> and <code>Renderer</code></li>
+ * <li><code>UIComponent</code></li>
+ * <li><code>Validator</code></li>
+ * </ul>
+ *
+ * <p>Note that any declared <em>factory</em> instances are explicitly
+ * <strong>NOT</strong> registered, allowing the mock object hierarchy
+ * of the Shale Test Framework to manage these APIs.</p>
+ *
+ * <p><strong>USAGE NOTE</strong> - If you are using an instance of this
+ * class within a subclass of <code>AbstractJsfTestCase</code> or
+ * <code>AbstractJmockJsfTestCase</code>, be sure you have completed the
+ * <code>setUp()</code> processing in this base class before calling one
+ * of the <code>parse()</code> methods.</p>
+ *
+ * @since 1.1
+ */
+public final class ConfigParser {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /** Creates a new instance of ConfigParser */
+ public ConfigParser() {
+ }
+
+
+ // ------------------------------------------------------ Manifest Constants
+
+
+ /**
+ * <p>Configuration resource URLs for the JSF RI.</p>
+ */
+ private static final String[] JSFRI_RESOURCES =
+ { "/com/sun/faces/jsf-ri-runtime.xml",
+ };
+
+
+ /**
+ * <p>Configuration resource URLs for Apache MyFaces.</p>
+ */
+ private static final String[] MYFACES_RESOURCES =
+ { "/org/apache/myfaces/resource/standard-faces-config.xml",
+ };
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The <code>Digester</code> instance we will use for parsing.</p>
+ */
+ private Digester digester = null;
+
+
+ // ------------------------------------------------------- Public Properties
+
+
+ /**
+ * <p>Return the URLs of the platform configuration resources for this
+ * application. The following platforms are currently supported:</p>
+ * <ul>
+ * <li>JavaServer Faces Reference Implementation (version 1.0 - 1.2)</li>
+ * <li>MyFaces (version 1.1)</li>
+ * </ul>
+ *
+ * <p>If MyFaces (version 1.2), currently under development, does not change
+ * the name of the configuration resource, it will be supported as well.</p>
+ */
+ public URL[] getPlatformURLs() {
+
+ URL[] urls = translate(JSFRI_RESOURCES);
+ if (urls[0] == null) {
+ urls = translate(MYFACES_RESOURCES);
+ }
+ return urls;
+
+ }
+
+
+ // ---------------------------------------------------------- Public Methods
+
+
+ /**
+ * <p>Parse the specified JavaServer Faces configuration resource, causing
+ * the appropriate JSF artifacts to be registered with the mock object
+ * hierarchy.</p>
+ *
+ * @param url <code>URL</code> of the configuration resource to parse
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception SAXException if a parsing error occurs
+ */
+ public void parse(URL url) throws IOException, SAXException {
+
+ // Acquire and configure the Digester instance we will use
+ Digester digester = digester();
+ ApplicationFactory factory = (ApplicationFactory)
+ FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
+ Application application = factory.getApplication();
+ digester.push(application);
+
+ // Perform the required parsing
+ try {
+ digester.parse(url);
+ } finally {
+ digester.clear();
+ }
+
+ }
+
+
+ /**
+ * <p>Parse the specified set of JavaServer Faces configuration resources,
+ * in the listed order, causing the appropriate JSF artifacts to be registered
+ * with the mock object hierarchy.</p>
+ *
+ * @param urls <code>URL</code>s of the configuration resources to parse
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception SAXException if a parsing error occurs
+ */
+ public void parse(URL[] urls) throws IOException, SAXException {
+
+ for (int i = 0; i < urls.length; i++) {
+ parse(urls[i]);
+ }
+
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>Return the <code>Digester</code> instance we will use for parsing,
+ * creating and configuring a new instance if necessary.</p>
+ */
+ private Digester digester() {
+
+ if (this.digester == null) {
+ this.digester = new Digester();
+ digester.addRule("faces-config/component", new ComponentRule());
+ digester.addCallMethod
+ ("faces-config/component/component-type", "setComponentType", 0);
+ digester.addCallMethod
+ ("faces-config/component/component-class", "setComponentClass", 0);
+ digester.addRule("faces-config/converter", new ConverterRule());
+ digester.addCallMethod
+ ("faces-config/converter/converter-id", "setConverterId", 0);
+ digester.addCallMethod
+ ("faces-config/converter/converter-class", "setConverterClass", 0);
+ digester.addCallMethod
+ ("faces-config/converter/converter-for-class", "setConverterForClass", 0);
+ digester.addRule("faces-config/render-kit", new RenderKitRule());
+ digester.addRule("faces-config/render-kit/render-kit-id", new RenderKitIdRule());
+ digester.addRule("faces-config/render-kit/renderer", new RendererRule());
+ digester.addCallMethod
+ ("faces-config/render-kit/renderer/component-family", "setComponentFamily", 0);
+ digester.addCallMethod
+ ("faces-config/render-kit/renderer/renderer-class", "setRendererClass", 0);
+ digester.addCallMethod
+ ("faces-config/render-kit/renderer/renderer-type", "setRendererType", 0);
+ digester.addRule("faces-config/validator", new ValidatorRule());
+ digester.addCallMethod
+ ("faces-config/validator/validator-id", "setValidatorId", 0);
+ digester.addCallMethod
+ ("faces-config/validator/validator-class", "setValidatorClass", 0);
+ }
+ return this.digester;
+
+ }
+
+
+ /**
+ * <p>Translate an array of resource names into an array of resource URLs.</p>
+ *
+ * @param names Resource names to translate
+ */
+ private URL[] translate(String[] names) {
+
+ URL[] results = new URL[names.length];
+ for (int i = 0; i < names.length; i++) {
+ results[i] = this.getClass().getResource(names[i]);
+ }
+ return results;
+
+ }
+
+
+ // --------------------------------------------------------- Private Classes
+
+
+ /**
+ * <p>Data bean that stores information related to a component.</p>
+ */
+ class ComponentBean {
+
+ private String componentClass;
+ public String getComponentClass() {
+ return this.componentClass;
+ }
+ public void setComponentClass(String componentClass) {
+ this.componentClass = componentClass;
+ }
+
+ private String componentType;
+ public String getComponentType() {
+ return this.componentType;
+ }
+ public void setComponentType(String componentType) {
+ this.componentType = componentType;
+ }
+
+ }
+
+
+ /**
+ * <p>Digester <code>Rule</code> for processing components.</p>
+ */
+ class ComponentRule extends Rule {
+
+ public void begin(String namespace, String name, Attributes attributes) {
+ getDigester().push(new ComponentBean());
+ }
+
+ public void end(String namespace, String name) {
+ ComponentBean bean = (ComponentBean) getDigester().pop();
+ Application application = (Application) getDigester().peek();
+ application.addComponent(bean.getComponentType(), bean.getComponentClass());
+ }
+
+ }
+
+
+ /**
+ * <p>Data bean that stores information related to a converter.</p>
+ */
+ class ConverterBean {
+
+ private String converterClass;
+ public String getConverterClass() {
+ return this.converterClass;
+ }
+ public void setConverterClass(String converterClass) {
+ this.converterClass = converterClass;
+ }
+
+ private String converterForClass;
+ public String getConverterForClass() {
+ return this.converterForClass;
+ }
+ public void setConverterForClass(String converterForClass) {
+ this.converterForClass = converterForClass;
+ }
+
+ private String converterId;
+ public String getConverterId() {
+ return this.converterId;
+ }
+ public void setConverterId(String converterId) {
+ this.converterId = converterId;
+ }
+
+ }
+
+
+ /**
+ * <p>Digester <code>Rule</code> for processing converers.</p>
+ */
+ class ConverterRule extends Rule {
+
+ public void begin(String namespace, String name, Attributes attributes) {
+ getDigester().push(new ConverterBean());
+ }
+
+ public void end(String namespace, String name) {
+ ConverterBean bean = (ConverterBean) getDigester().pop();
+ Application application = (Application) getDigester().peek();
+ if (bean.getConverterId() != null) {
+ application.addConverter(bean.getConverterId(), bean.getConverterClass());
+ } else {
+ Class clazz = null;
+ try {
+ clazz = this.getClass().getClassLoader().loadClass(bean.getConverterForClass());
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("java.lang.ClassNotFoundException: "
+ + bean.getConverterForClass());
+ }
+ application.addConverter(clazz, bean.getConverterClass());
+ }
+ }
+
+ }
+
+
+ /**
+ * <p>Digester <code>Rule</code> for processing render kits.</p>
+ */
+ class RenderKitRule extends Rule {
+
+ public void begin(String namespace, String name, Attributes attributes) {
+ RenderKitFactory factory = (RenderKitFactory)
+ FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ getDigester().push(factory.getRenderKit(null, RenderKitFactory.HTML_BASIC_RENDER_KIT));
+ }
+
+ public void end(String namespace, String name) {
+ getDigester().pop();
+ }
+
+ }
+
+
+ /**
+ * <p>Digester <code>Rule</code> for processing render kit identifiers.</p>
+ */
+ class RenderKitIdRule extends Rule {
+
+ public void body(String namespace, String name, String text) {
+ String renderKitId = text.trim();
+ RenderKitFactory factory = (RenderKitFactory)
+ FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ RenderKit renderKit = factory.getRenderKit(null, renderKitId);
+ if (renderKit == null) {
+ renderKit = new MockRenderKit();
+ factory.addRenderKit(renderKitId, renderKit);
+ }
+ digester.pop();
+ digester.push(renderKit);
+ }
+
+ }
+
+
+ /**
+ * <p>Data bean that stores information related to a renderer.</p>
+ */
+ class RendererBean {
+
+ private String componentFamily;
+ public String getComponentFamily() {
+ return this.componentFamily;
+ }
+ public void setComponentFamily(String componentFamily) {
+ this.componentFamily = componentFamily;
+ }
+
+ private String rendererClass;
+ public String getRendererClass() {
+ return this.rendererClass;
+ }
+ public void setRendererClass(String rendererClass) {
+ this.rendererClass = rendererClass;
+ }
+
+ private String rendererType;
+ public String getRendererType() {
+ return this.rendererType;
+ }
+ public void setRendererType(String rendererType) {
+ this.rendererType = rendererType;
+ }
+
+ }
+
+
+ /**
+ * <p>Digester <code>Rule</code> for processing renderers.</p>
+ */
+ class RendererRule extends Rule {
+
+ public void begin(String namespace, String name, Attributes attributes) {
+ getDigester().push(new RendererBean());
+ }
+
+ public void end(String namespace, String name) {
+ RendererBean bean = (RendererBean) getDigester().pop();
+ RenderKit kit = (RenderKit) getDigester().peek();
+ Renderer renderer = null;
+ Class clazz = null;
+ try {
+ clazz = this.getClass().getClassLoader().loadClass(bean.getRendererClass());
+ renderer = (Renderer) clazz.newInstance();
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Exception while trying to instantiate"
+ + " renderer class '" + bean.getRendererClass() + "' : "
+ + e.getMessage());
+ }
+ kit.addRenderer(bean.getComponentFamily(), bean.getRendererType(),
+ renderer);
+ }
+
+ }
+
+
+ /**
+ * <p>Data bean that stores information related to a validator.</p>
+ */
+ class ValidatorBean {
+
+ private String validatorClass;
+ public String getValidatorClass() {
+ return this.validatorClass;
+ }
+ public void setValidatorClass(String validatorClass) {
+ this.validatorClass = validatorClass;
+ }
+
+ private String validatorId;
+ public String getValidatorId() {
+ return this.validatorId;
+ }
+ public void setValidatorId(String validatorId) {
+ this.validatorId = validatorId;
+ }
+
+ }
+
+
+ /**
+ * <p>Digester <code>Rule</code> for processing validators.</p>
+ */
+ class ValidatorRule extends Rule {
+
+ public void begin(String namespace, String name, Attributes attributes) {
+ getDigester().push(new ValidatorBean());
+ }
+
+ public void end(String namespace, String name) {
+ ValidatorBean bean = (ValidatorBean) getDigester().pop();
+ Application application = (Application) getDigester().peek();
+ application.addValidator(bean.getValidatorId(), bean.getValidatorClass());
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/config/package.html b/shale-test/src/main/java/org/apache/shale/test/config/package.html
new file mode 100644
index 0000000..c73f764
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/config/package.html
@@ -0,0 +1,30 @@
+<body>
+<!--
+ 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.
+-->
+<p>This package contains a utility class,
+<a href="ConfigParser.html">ConfigParser</a>, which provides a
+<code>parse()</code> method that can parse JavaServer Faces configuration
+resources. It supports the registration, in the mock object hierarchy
+set up by an instance of <code>AbstractJsfTestCase</code> or
+<code>AbstractJmockJsfTestCase</code>, of the following JSF artifacts:</p>
+<ul>
+ <li><code>Converter</code> (by-id and by-class)</li>
+ <li><code>RenderKit</code> and <code>Renderer</code></li>
+ <li><code>UIComponent</code></li>
+ <li><code>Validator</code></li>
+</ul>
+</body>
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/AbstractELResolver.java b/shale-test/src/main/java/org/apache/shale/test/el/AbstractELResolver.java
new file mode 100644
index 0000000..c3c9df2
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/AbstractELResolver.java
@@ -0,0 +1,71 @@
+/*
+ * 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.shale.test.el;
+
+import java.beans.FeatureDescriptor;
+import javax.el.ELResolver;
+
+/**
+ * <p>Convenience base class for EL resolvers.</p>
+ */
+abstract class AbstractELResolver extends ELResolver {
+
+
+
+ // ------------------------------------------------------- Protected Methods
+
+
+ /**
+ * <p>Create and return a <code>FeatureDescriptor</code> configured with
+ * the specified arguments.</p>
+ *
+ * @param name Feature name
+ * @param displayName Display name
+ * @param description Short description
+ * @param expert Flag indicating this feature is for experts
+ * @param hidden Flag indicating this feature should be hidden
+ * @param preferred Flag indicating this feature is the preferred one
+ * among features of the same type
+ * @param type Runtime type of this feature
+ * @param designTime Flag indicating feature is resolvable at design time
+ */
+ protected FeatureDescriptor descriptor(String name, String displayName,
+ String description, boolean expert, boolean hidden, boolean preferred,
+ Object type, boolean designTime) {
+
+ FeatureDescriptor descriptor = new FeatureDescriptor();
+
+ descriptor.setName(name);
+ descriptor.setDisplayName(displayName);
+ descriptor.setShortDescription(description);
+ descriptor.setExpert(expert);
+ descriptor.setHidden(hidden);
+ descriptor.setPreferred(preferred);
+ descriptor.setValue(ELResolver.TYPE, type);
+ if (designTime) {
+ descriptor.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE);
+ } else {
+ descriptor.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, Boolean.FALSE);
+ }
+
+ return descriptor;
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/FacesImplicitObjectELResolver.java b/shale-test/src/main/java/org/apache/shale/test/el/FacesImplicitObjectELResolver.java
new file mode 100644
index 0000000..f79c989
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/FacesImplicitObjectELResolver.java
@@ -0,0 +1,272 @@
+/*
+ * 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.shale.test.el;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotFoundException;
+import javax.el.PropertyNotWritableException;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p><code>ELResolver</code> implementation that accesses implicit objects
+ * in the current request context. See the JSF 1.2 Specification, section
+ * 5.6.2.1, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.4
+ */
+public class FacesImplicitObjectELResolver extends AbstractELResolver {
+
+
+ /**
+ * <p>The names of all implicit objects recognized by this resolver.</p>
+ */
+ private static final String[] NAMES =
+ { "application", "applicationScope", "cookie", "facesContext",
+ "header", "headerValues", "initParam", "param", "paramValues",
+ "request", "requestScope", "session", "sessionScope", "view" };
+
+
+ /**
+ * <p>The property types corresponding to the implicit object names.</p>
+ */
+ private static final Class[] TYPES =
+ { Object.class, Map.class, Map.class, FacesContext.class,
+ Map.class, Map.class, Map.class, Map.class, Map.class,
+ Object.class, Map.class, Object.class, Map.class, UIViewRoot.class };
+
+
+ /**
+ * <p>The settable value types corresponding to the implicit
+ * object names.</p>
+ */
+ private static final Class[] VALUES =
+ { null, Object.class, null, null,
+ null, null, null, null, null,
+ null, Object.class, null, Object.class, null };
+
+
+ /**
+ * <p>Return the most general type this resolver accepts for the
+ * <code>property</code> argument.</p>
+ */
+ public Class getCommonPropertyType(ELContext context, Object base) {
+
+ if (base != null) {
+ return null;
+ } else {
+ return String.class;
+ }
+
+ }
+
+
+ /**
+ * <p>Return an <code>Iterator</code> over the attributes that this
+ * resolver knows how to deal with.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ */
+ public Iterator getFeatureDescriptors(ELContext context, Object base) {
+
+ if (base != null) {
+ return null;
+ }
+
+ // Create the variables we will need
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ List descriptors = new ArrayList();
+
+ // Add feature descriptors for each implicit object
+ for (int i = 0; i < NAMES.length; i++) {
+ descriptors.add(descriptor(NAMES[i], NAMES[i], NAMES[i],
+ false, false, true, TYPES[i], true));
+ }
+
+ // Return the accumulated descriptors
+ return descriptors.iterator();
+
+ }
+
+
+
+ /**
+ * <p>Return the Java type of the specified property.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Class getType(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return null;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+ String name = property.toString();
+ for (int i = 0; i < NAMES.length; i++) {
+ if (name.equals(NAMES[i])) {
+ context.setPropertyResolved(true);
+ return VALUES[i];
+ }
+ }
+ return null;
+
+ }
+
+
+ /**
+ * <p>Return an existing scoped object for the specified name (if any);
+ * otherwise, return <code>null</code>.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Object getValue(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return null;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ExternalContext econtext = fcontext.getExternalContext();
+ String name = property.toString();
+
+ if (name.equals("application")) {
+ context.setPropertyResolved(true);
+ return econtext.getContext();
+ } else if (name.equals("applicationScope")) {
+ context.setPropertyResolved(true);
+ return econtext.getApplicationMap();
+ } else if (name.equals("cookie")) {
+ context.setPropertyResolved(true);
+ return econtext.getRequestCookieMap();
+ } else if (name.equals("facesContext")) {
+ context.setPropertyResolved(true);
+ return fcontext;
+ } else if (name.equals("header")) {
+ context.setPropertyResolved(true);
+ return econtext.getRequestHeaderMap();
+ } else if (name.equals("headerValues")) {
+ context.setPropertyResolved(true);
+ return econtext.getRequestHeaderValuesMap();
+ } else if (name.equals("initParam")) {
+ context.setPropertyResolved(true);
+ return econtext.getInitParameterMap();
+ } else if (name.equals("param")) {
+ context.setPropertyResolved(true);
+ return econtext.getRequestParameterMap();
+ } else if (name.equals("paramValues")) {
+ context.setPropertyResolved(true);
+ return econtext.getRequestParameterValuesMap();
+ } else if (name.equals("request")) {
+ context.setPropertyResolved(true);
+ return econtext.getRequest();
+ } else if (name.equals("requestScope")) {
+ context.setPropertyResolved(true);
+ return econtext.getRequestMap();
+ } else if (name.equals("session")) {
+ context.setPropertyResolved(true);
+ return econtext.getSession(true);
+ } else if (name.equals("sessionScope")) {
+ context.setPropertyResolved(true);
+ return econtext.getSessionMap();
+ } else if (name.equals("view")) {
+ context.setPropertyResolved(true);
+ return fcontext.getViewRoot();
+ }
+
+ return null;
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the specified property is read only.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public boolean isReadOnly(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return false;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+ String name = property.toString();
+ for (int i = 0; i < NAMES.length; i++) {
+ if (name.equals(NAMES[i])) {
+ context.setPropertyResolved(true);
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+
+
+ /**
+ * <p>Set the value of a scoped object for the specified name.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ * @param value New value to be set
+ */
+ public void setValue(ELContext context, Object base, Object property, Object value) {
+
+ if (base != null) {
+ return;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+
+ String name = property.toString();
+ for (int i = 0; i < NAMES.length; i++) {
+ if (name.equals(NAMES[i])) {
+ context.setPropertyResolved(true);
+ throw new PropertyNotWritableException(name);
+ }
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/FacesPropertyResolverChainWrapper.java b/shale-test/src/main/java/org/apache/shale/test/el/FacesPropertyResolverChainWrapper.java
new file mode 100644
index 0000000..27ff077
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/FacesPropertyResolverChainWrapper.java
@@ -0,0 +1,233 @@
+/*
+ * 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.shale.test.el;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.faces.context.FacesContext;
+import javax.faces.el.EvaluationException;
+import javax.faces.el.PropertyResolver;
+
+/**
+ * <p><code>ELResolver</code> implementation that wraps the legacy (JSF 1.1)
+ * <code>PropertyResolver</code> chain. See the JSF 1.2 Specification, section
+ * 5.6.1.6, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.4
+ */
+public class FacesPropertyResolverChainWrapper extends AbstractELResolver {
+
+
+ /**
+ * <p>Return the most general type this resolver accepts for the
+ * <code>property</code> argument.</p>
+ */
+ public Class getCommonPropertyType(ELContext context, Object base) {
+
+ if (base != null) {
+ return null;
+ } else {
+ return Object.class;
+ }
+
+ }
+
+
+ /**
+ * <p>Return an <code>Iterator</code> over the attributes that this
+ * resolver knows how to deal with.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ */
+ public Iterator getFeatureDescriptors(ELContext context, Object base) {
+
+ return null;
+
+ }
+
+
+
+ /**
+ * <p>Evaluate with the legacy property resolver chain and return
+ * the value.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Class getType(ELContext context, Object base, Object property) {
+
+ if ((base == null) || (property == null)) {
+ return null;
+ }
+
+ context.setPropertyResolved(true);
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ELContext elContext = fcontext.getELContext();
+ PropertyResolver pr = fcontext.getApplication().getPropertyResolver();
+
+ if ((base instanceof List) || base.getClass().isArray()) {
+ Integer index = (Integer) fcontext.getApplication().getExpressionFactory().
+ coerceToType(property, Integer.class);
+ try {
+ return pr.getType(base, index.intValue());
+ } catch (EvaluationException e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+ } else {
+ try {
+ return pr.getType(base, property);
+ } catch (EvaluationException e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+ }
+
+ }
+
+
+ /**
+ * <p>Evaluate with the legacy property resolver chain and return
+ * the value.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Object getValue(ELContext context, Object base, Object property) {
+
+ if ((base == null) || (property == null)) {
+ return null;
+ }
+
+ context.setPropertyResolved(true);
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ELContext elContext = fcontext.getELContext();
+ PropertyResolver pr = fcontext.getApplication().getPropertyResolver();
+
+ if ((base instanceof List) || base.getClass().isArray()) {
+ Integer index = (Integer) fcontext.getApplication().getExpressionFactory().
+ coerceToType(property, Integer.class);
+ try {
+ return pr.getValue(base, index.intValue());
+ } catch (EvaluationException e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+ } else {
+ try {
+ return pr.getValue(base, property);
+ } catch (EvaluationException e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+ }
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the specified property is read only.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public boolean isReadOnly(ELContext context, Object base, Object property) {
+
+ if ((base == null) || (property == null)) {
+ return false;
+ }
+
+ context.setPropertyResolved(true);
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ELContext elContext = fcontext.getELContext();
+ PropertyResolver pr = fcontext.getApplication().getPropertyResolver();
+
+ if ((base instanceof List) || base.getClass().isArray()) {
+ Integer index = (Integer) fcontext.getApplication().getExpressionFactory().
+ coerceToType(property, Integer.class);
+ try {
+ return pr.isReadOnly(base, index.intValue());
+ } catch (EvaluationException e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+ } else {
+ try {
+ return pr.isReadOnly(base, property);
+ } catch (EvaluationException e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+ }
+
+ }
+
+
+
+ /**
+ * <p>Set the value of a property for the specified name.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ * @param value New value to be set
+ */
+ public void setValue(ELContext context, Object base, Object property, Object value) {
+
+ if ((base == null) || (property == null)) {
+ return;
+ }
+
+ context.setPropertyResolved(true);
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ELContext elContext = fcontext.getELContext();
+ PropertyResolver pr = fcontext.getApplication().getPropertyResolver();
+
+ if ((base instanceof List) || base.getClass().isArray()) {
+ Integer index = (Integer) fcontext.getApplication().getExpressionFactory().
+ coerceToType(property, Integer.class);
+ try {
+ pr.setValue(base, index.intValue(), value);
+ } catch (EvaluationException e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+ } else {
+ try {
+ pr.setValue(base, property, value);
+ } catch (EvaluationException e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/FacesResourceBundleELResolver.java b/shale-test/src/main/java/org/apache/shale/test/el/FacesResourceBundleELResolver.java
new file mode 100644
index 0000000..7af0302
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/FacesResourceBundleELResolver.java
@@ -0,0 +1,212 @@
+/*
+ * 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.shale.test.el;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ResourceBundle;
+import java.util.Map.Entry;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotFoundException;
+import javax.el.PropertyNotWritableException;
+import javax.faces.context.FacesContext;
+
+import org.apache.shale.test.mock.MockApplication12;
+
+/**
+ * <p><code>ELResolver</code> implementation that accesses resource bundles
+ * in the current application. See the JSF 1.2 Specification, section
+ * 5.6.1.3, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.4
+ */
+public class FacesResourceBundleELResolver extends AbstractELResolver {
+
+
+ /**
+ * <p>Return the most general type this resolver accepts for the
+ * <code>property</code> argument.</p>
+ */
+ public Class getCommonPropertyType(ELContext context, Object base) {
+
+ if (base != null) {
+ return null;
+ } else {
+ return String.class;
+ }
+
+ }
+
+
+ /**
+ * <p>Return an <code>Iterator</code> over the attributes that this
+ * resolver knows how to deal with.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ */
+ public Iterator getFeatureDescriptors(ELContext context, Object base) {
+
+ if (base != null) {
+ return null;
+ }
+
+ // Create the variables we will need
+ List descriptors = new ArrayList();
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ MockApplication12 application =
+ (MockApplication12) fcontext.getApplication();
+ String key = null;
+ Object value = null;
+
+ // Create a feature descriptor for each configured resource bundle
+ Iterator entries = application.getResourceBundles().entrySet().iterator();
+ while (entries.hasNext()) {
+ Entry entry = (Entry) entries.next();
+ key = (String) entry.getKey();
+ value = entry.getValue();
+ descriptors.add(descriptor(key, key, "Resource Bundle " + key,
+ false, false, true,
+ ResourceBundle.class, true));
+ }
+
+ // Return the accumulated descriptors
+ return descriptors.iterator();
+
+ }
+
+
+ /**
+ * <p>Return the Java type of the specified property.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Class getType(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return null;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ResourceBundle bundle =
+ fcontext.getApplication().getResourceBundle(fcontext, property.toString());
+ if (bundle != null) {
+ context.setPropertyResolved(true);
+ return ResourceBundle.class;
+ }
+ return null;
+
+ }
+
+
+ /**
+ * <p>Return a resource bundle for the specified name (if any);
+ * otherwise, return <code>null</code>.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Object getValue(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return null;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ResourceBundle bundle =
+ fcontext.getApplication().getResourceBundle(fcontext, property.toString());
+ if (bundle != null) {
+ context.setPropertyResolved(true);
+ return bundle;
+ }
+ return null;
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the specified property is read only.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public boolean isReadOnly(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return false;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ResourceBundle bundle =
+ fcontext.getApplication().getResourceBundle(fcontext, property.toString());
+ if (bundle != null) {
+ context.setPropertyResolved(true);
+ return true;
+ }
+ return false;
+
+ }
+
+
+
+ /**
+ * <p>Set the value of a scoped object for the specified name.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ * @param value New value to be set
+ */
+ public void setValue(ELContext context, Object base, Object property, Object value) {
+
+ if (base != null) {
+ return;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ResourceBundle bundle =
+ fcontext.getApplication().getResourceBundle(fcontext, property.toString());
+ if (bundle != null) {
+ context.setPropertyResolved(true);
+ throw new PropertyNotWritableException(property.toString());
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/FacesScopedAttributeELResolver.java b/shale-test/src/main/java/org/apache/shale/test/el/FacesScopedAttributeELResolver.java
new file mode 100644
index 0000000..a9a5e23
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/FacesScopedAttributeELResolver.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.test.el;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotFoundException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p><code>ELResolver</code> implementation that accesses scoped variables
+ * in the current request context. See the JSF 1.2 Specification, section
+ * 5.6.2.7, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.4
+ */
+public class FacesScopedAttributeELResolver extends AbstractELResolver {
+
+
+ /**
+ * <p>Return the most general type this resolver accepts for the
+ * <code>property</code> argument.</p>
+ */
+ public Class getCommonPropertyType(ELContext context, Object base) {
+
+ if (base != null) {
+ return null;
+ } else {
+ return String.class;
+ }
+
+ }
+
+
+ /**
+ * <p>Return an <code>Iterator</code> over the attributes that this
+ * resolver knows how to deal with.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ */
+ public Iterator getFeatureDescriptors(ELContext context, Object base) {
+
+ if (base != null) {
+ return null;
+ }
+
+ // Create the variables we will need
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ExternalContext econtext = fcontext.getExternalContext();
+ List descriptors = new ArrayList();
+ Map map = null;
+ Set set = null;
+ Iterator items = null;
+ String key = null;
+ Object value = null;
+
+ // Add feature descriptors for request scoped attributes
+ set = econtext.getRequestMap().entrySet();
+ items = set.iterator();
+ while (items.hasNext()) {
+ Entry item = (Entry) items.next();
+ key = (String) item.getKey();
+ value = item.getValue();
+ descriptors.add(descriptor(key, key, "Request Scope Attribute " + key,
+ false, false, true, value.getClass(), true));
+ }
+
+ // Add feature descriptors for session scoped attributes
+ set = econtext.getSessionMap().entrySet();
+ items = set.iterator();
+ while (items.hasNext()) {
+ Entry item = (Entry) items.next();
+ key = (String) item.getKey();
+ value = item.getValue();
+ descriptors.add(descriptor(key, key, "Session Scope Attribute " + key,
+ false, false, true, value.getClass(), true));
+ }
+
+ // Add feature descriptors for application scoped attributes
+ set = econtext.getApplicationMap().entrySet();
+ items = set.iterator();
+ while (items.hasNext()) {
+ Entry item = (Entry) items.next();
+ key = (String) item.getKey();
+ value = item.getValue();
+ descriptors.add(descriptor(key, key, "Application Scope Attribute " + key,
+ false, false, true, value.getClass(), true));
+ }
+
+ // Return the accumulated descriptors
+ return descriptors.iterator();
+
+ }
+
+
+
+ /**
+ * <p>Return the Java type of the specified property.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Class getType(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return null;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+ context.setPropertyResolved(true);
+ return Object.class;
+
+ }
+
+
+ /**
+ * <p>Return an existing scoped object for the specified name (if any);
+ * otherwise, return <code>null</code>.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Object getValue(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return null;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ExternalContext econtext = fcontext.getExternalContext();
+ Object value = null;
+ value = econtext.getRequestMap().get(property);
+ if (value != null) {
+ context.setPropertyResolved(true);
+ return value;
+ }
+ value = econtext.getSessionMap().get(property);
+ if (value != null) {
+ context.setPropertyResolved(true);
+ return value;
+ }
+ value = econtext.getApplicationMap().get(property);
+ if (value != null) {
+ context.setPropertyResolved(true);
+ return value;
+ }
+
+ return null;
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the specified property is read only.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public boolean isReadOnly(ELContext context, Object base, Object property) {
+
+ if (base == null) {
+ context.setPropertyResolved(true);
+ return false;
+ }
+ return false;
+
+ }
+
+
+
+ /**
+ * <p>Set the value of a scoped object for the specified name.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ * @param value New value to be set
+ */
+ public void setValue(ELContext context, Object base, Object property, Object value) {
+
+ if (base != null) {
+ return;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+
+ context.setPropertyResolved(true);
+ String key = property.toString();
+ Object result = null;
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ExternalContext econtext = fcontext.getExternalContext();
+
+ if (econtext.getRequestMap().containsKey(property)) {
+ econtext.getRequestMap().put(key, value);
+ } else if (econtext.getSessionMap().containsKey(property)) {
+ econtext.getSessionMap().put(key, value);
+ } else if (econtext.getApplicationMap().containsKey(property)) {
+ econtext.getApplicationMap().put(key, value);
+ } else {
+ econtext.getRequestMap().put(key, value);
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/FacesVariableResolverChainWrapper.java b/shale-test/src/main/java/org/apache/shale/test/el/FacesVariableResolverChainWrapper.java
new file mode 100644
index 0000000..aa22068
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/FacesVariableResolverChainWrapper.java
@@ -0,0 +1,162 @@
+/*
+ * 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.shale.test.el;
+
+import java.util.Iterator;
+
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.PropertyNotFoundException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.el.VariableResolver;
+
+/**
+ * <p><code>ELResolver</code> implementation that wraps the legacy (JSF 1.1)
+ * <code>VariableResolver</code> chain. See the JSF 1.2 Specification, section
+ * 5.6.1.5, for requirements implemented by this class.</p>
+ *
+ * @since 1.0.4
+ */
+public class FacesVariableResolverChainWrapper extends AbstractELResolver {
+
+
+ /**
+ * <p>Return the most general type this resolver accepts for the
+ * <code>property</code> argument.</p>
+ */
+ public Class getCommonPropertyType(ELContext context, Object base) {
+
+ if (base != null) {
+ return null;
+ } else {
+ return String.class;
+ }
+
+ }
+
+
+ /**
+ * <p>Return an <code>Iterator</code> over the attributes that this
+ * resolver knows how to deal with.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ */
+ public Iterator getFeatureDescriptors(ELContext context, Object base) {
+
+ return null;
+
+ }
+
+
+
+ /**
+ * <p>Return the Java type of the specified property.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Class getType(ELContext context, Object base, Object property) {
+
+ if ((base == null) && (property == null)) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+ return null;
+
+ }
+
+
+ /**
+ * <p>Evaluate with the legacy variable resolver chain and return
+ * the value.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public Object getValue(ELContext context, Object base, Object property) {
+
+ if (base != null) {
+ return null;
+ }
+ if (property == null) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ExternalContext econtext = fcontext.getExternalContext();
+ String name = property.toString();
+
+ ELContext elContext = fcontext.getELContext();
+ VariableResolver vr = fcontext.getApplication().getVariableResolver();
+ try {
+ Object value = vr.resolveVariable(fcontext, name);
+ if (value != null) {
+ context.setPropertyResolved(true);
+ }
+ return value;
+ } catch (Exception e) {
+ context.setPropertyResolved(false);
+ throw new ELException(e);
+ }
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the specified property is read only.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ */
+ public boolean isReadOnly(ELContext context, Object base, Object property) {
+
+ if ((base == null) && (property == null)) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+ return false;
+
+ }
+
+
+
+ /**
+ * <p>Set the value of a scoped object for the specified name.</p>
+ *
+ * @param context <code>ELContext</code> for evaluating this value
+ * @param base Base object against which this evaluation occurs
+ * (must be null because we are evaluating a top level variable)
+ * @param property Property name to be accessed
+ * @param value New value to be set
+ */
+ public void setValue(ELContext context, Object base, Object property, Object value) {
+
+ if ((base == null) && (property == null)) {
+ throw new PropertyNotFoundException("No property specified");
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/MockELContext.java b/shale-test/src/main/java/org/apache/shale/test/el/MockELContext.java
new file mode 100644
index 0000000..237499d
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/MockELContext.java
@@ -0,0 +1,124 @@
+/*
+ * 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.shale.test.el;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import javax.el.FunctionMapper;
+import javax.el.VariableMapper;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>ELContext</code>.</p>
+ *
+ * @since 1.0.4
+ */
+
+public class MockELContext extends ELContext {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /** Creates a new instance of MockELContext */
+ public MockELContext() {
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private Map contexts = new HashMap();
+ private FunctionMapper functionMapper = new MockFunctionMapper();
+ private Locale locale = Locale.getDefault();
+ private boolean propertyResolved;
+ private VariableMapper variableMapper = new MockVariableMapper();
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+
+ // ------------------------------------------------------- ELContext Methods
+
+
+ /** {@inheritDoc} */
+ public Object getContext(Class key) {
+ if (key == null) {
+ throw new NullPointerException();
+ }
+ return contexts.get(key);
+ }
+
+
+ /** {@inheritDoc} */
+ public ELResolver getELResolver() {
+ FacesContext context = FacesContext.getCurrentInstance();
+ return context.getApplication().getELResolver();
+ }
+
+
+ /** {@inheritDoc} */
+ public FunctionMapper getFunctionMapper() {
+ return this.functionMapper;
+ }
+
+
+ /** {@inheritDoc} */
+ public Locale getLocale() {
+ return this.locale;
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isPropertyResolved() {
+ return this.propertyResolved;
+ }
+
+
+ /** {@inheritDoc} */
+ public void putContext(Class key, Object value) {
+ if ((key == null) || (value == null)) {
+ throw new NullPointerException();
+ }
+ contexts.put(key, value);
+ }
+
+
+ /** {@inheritDoc} */
+ public void setPropertyResolved(boolean propertyResolved) {
+ this.propertyResolved = propertyResolved;
+ }
+
+
+ /** {@inheritDoc} */
+ public VariableMapper getVariableMapper() {
+ return this.variableMapper;
+ }
+
+
+ /** {@inheritDoc} */
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/MockExpressionFactory.java b/shale-test/src/main/java/org/apache/shale/test/el/MockExpressionFactory.java
new file mode 100644
index 0000000..e973008
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/MockExpressionFactory.java
@@ -0,0 +1,257 @@
+/*
+ * 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.shale.test.el;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.MethodExpression;
+import javax.el.ValueExpression;
+
+/**
+ * <p>Mock implementation of <code>ExpressionFactory</code>.</p>
+ *
+ * @since 1.0.4
+ */
+public class MockExpressionFactory extends ExpressionFactory {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /** Creates a new instance of MockExpressionFactory */
+ public MockExpressionFactory() {
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>Literal numeric value for zero.</p>
+ */
+ private static final Integer ZERO = new Integer(0);
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+
+ // ----------------------------------------------- ExpressionFactory Methods
+
+
+ /** {@inheritDoc} */
+ public Object coerceToType(Object object, Class targetType) {
+
+ // Check for no conversion necessary
+ if ((targetType == null) || Object.class.equals(targetType)) {
+ return object;
+ }
+
+ // Coerce to String if appropriate
+ if (String.class.equals(targetType)) {
+ if (object == null) {
+ return "";
+ } else if (object instanceof String) {
+ return (String) object;
+ } else {
+ return object.toString();
+ }
+ }
+
+ // Coerce to Number (or a subclass of Number) if appropriate
+ if (isNumeric(targetType)) {
+ if (object == null) {
+ return coerce(ZERO, targetType);
+ } else if ("".equals(object)) {
+ return coerce(ZERO, targetType);
+ } else if (object instanceof String) {
+ return coerce((String) object, targetType);
+ } else if (isNumeric(object.getClass())) {
+ return coerce((Number) object, targetType);
+ }
+ throw new IllegalArgumentException("Cannot convert " + object + " to Number");
+ }
+
+ // Coerce to Boolean if appropriate
+ if (Boolean.class.equals(targetType) || (Boolean.TYPE == targetType)) {
+ if (object == null) {
+ return Boolean.FALSE;
+ } else if ("".equals(object)) {
+ return Boolean.FALSE;
+ } else if ((object instanceof Boolean) || (object.getClass() == Boolean.TYPE)) {
+ return (Boolean) object;
+ } else if (object instanceof String) {
+ return Boolean.valueOf((String) object);
+ }
+ throw new IllegalArgumentException("Cannot convert " + object + " to Boolean");
+ }
+
+ // Coerce to Character if appropriate
+ if (Character.class.equals(targetType) || (Character.TYPE == targetType)) {
+ if (object == null) {
+ return new Character((char) 0);
+ } else if ("".equals(object)) {
+ return new Character((char) 0);
+ } else if (object instanceof String) {
+ return new Character(((String) object).charAt(0));
+ } else if (isNumeric(object.getClass())) {
+ return new Character((char) ((Number) object).shortValue());
+ } else if ((object instanceof Character) || (object.getClass() == Character.TYPE)) {
+ return (Character) object;
+ }
+ throw new IllegalArgumentException("Cannot convert " + object + " to Character");
+ }
+
+ // Is the specified value type-compatible already?
+ if ((object != null) && targetType.isAssignableFrom(object.getClass())) {
+ return object;
+ }
+
+ // We do not know how to perform this conversion
+ throw new IllegalArgumentException("Cannot convert " + object + " to " + targetType.getName());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public MethodExpression createMethodExpression(ELContext context,
+ String expression,
+ Class expectedType,
+ Class[] signature) {
+
+ return new MockMethodExpression(expression, signature, expectedType);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ValueExpression createValueExpression(ELContext context,
+ String expression,
+ Class expectedType) {
+
+ return new MockValueExpression(expression, expectedType);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ValueExpression createValueExpression(Object instance,
+ Class expectedType) {
+
+ return new MockVariableValueExpression(instance, expectedType);
+
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>Coerce the specified value to the specified Number subclass.</p>
+ *
+ * @param value Value to be coerced
+ * @param type Destination type
+ */
+ private Number coerce(Number value, Class type) {
+
+ if ((type == Byte.TYPE) || (type == Byte.class)) {
+ return new Byte(value.byteValue());
+ } else if ((type == Double.TYPE) || (type == Double.class)) {
+ return new Double(value.doubleValue());
+ } else if ((type == Float.TYPE) || (type == Float.class)) {
+ return new Float(value.floatValue());
+ } else if ((type == Integer.TYPE) || (type == Integer.class)) {
+ return new Integer(value.intValue());
+ } else if ((type == Long.TYPE) || (type == Long.class)) {
+ return new Long(value.longValue());
+ } else if ((type == Short.TYPE) || (type == Short.class)) {
+ return new Short(value.shortValue());
+ } else if (type == BigDecimal.class) {
+ if (value instanceof BigDecimal) {
+ return (BigDecimal) value;
+ } else if (value instanceof BigInteger) {
+ return new BigDecimal((BigInteger) value);
+ } else {
+ return new BigDecimal(((Number) value).doubleValue());
+ }
+ } else if (type == BigInteger.class) {
+ if (value instanceof BigInteger) {
+ return (BigInteger) value;
+ } else if (value instanceof BigDecimal) {
+ return ((BigDecimal) value).toBigInteger();
+ } else {
+ return BigInteger.valueOf(((Number) value).longValue());
+ }
+ }
+ throw new IllegalArgumentException("Cannot convert " + value + " to " + type.getName());
+
+ }
+
+
+ /**
+ * <p>Coerce the specified value to the specified Number subclass.</p>
+ *
+ * @param value Value to be coerced
+ * @param type Destination type
+ */
+ private Number coerce(String value, Class type) {
+
+ if ((type == Byte.TYPE) || (type == Byte.class)) {
+ return Byte.valueOf(value);
+ } else if ((type == Double.TYPE) || (type == Double.class)) {
+ return Double.valueOf(value);
+ } else if ((type == Float.TYPE) || (type == Float.class)) {
+ return Float.valueOf(value);
+ } else if ((type == Integer.TYPE) || (type == Integer.class)) {
+ return Integer.valueOf(value);
+ } else if ((type == Long.TYPE) || (type == Long.class)) {
+ return Long.valueOf(value);
+ } else if ((type == Short.TYPE) || (type == Short.class)) {
+ return Short.valueOf(value);
+ } else if (type == BigDecimal.class) {
+ return new BigDecimal(value);
+ } else if (type == BigInteger.class) {
+ return new BigInteger(value);
+ }
+ throw new IllegalArgumentException("Cannot convert " + value + " to " + type.getName());
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the specified type is numeric.</p>
+ *
+ * @param type Type to check
+ */
+ private boolean isNumeric(Class type) {
+
+ return
+ (type == Byte.TYPE) || (type == Byte.class)
+ || (type == Double.TYPE) || (type == Double.class)
+ || (type == Float.TYPE) || (type == Float.class)
+ || (type == Integer.TYPE) || (type == Integer.class)
+ || (type == Long.TYPE) || (type == Long.class)
+ || (type == Short.TYPE) || (type == Short.class)
+ || (type == BigDecimal.class) || (type == BigInteger.class);
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/MockFunctionMapper.java b/shale-test/src/main/java/org/apache/shale/test/el/MockFunctionMapper.java
new file mode 100644
index 0000000..1bed5a2
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/MockFunctionMapper.java
@@ -0,0 +1,77 @@
+/*
+ * 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.shale.test.el;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import javax.el.FunctionMapper;
+
+/**
+ * <p>Mock implementation of <code>FunctionMapper</code>.</p>
+ *
+ * @since 1.0.4
+ */
+
+public class MockFunctionMapper extends FunctionMapper {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /** Creates a new instance of MockFunctionMapper */
+ public MockFunctionMapper() {
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>Map of <code>Method</code> descriptors for static methods, keyed by
+ * a string composed of the prefix (or "" if none), a ":", and the local name.</p>
+ */
+ private Map functions = new HashMap();
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ /**
+ * <p>Store a mapping of the specified prefix and localName to the
+ * specified method, which must be static.</p>
+ */
+ public void mapFunction(String prefix, String localName, Method method) {
+
+ functions.put(prefix + ":" + localName, method);
+
+ }
+
+
+ // -------------------------------------------------- FunctionMapper Methods
+
+
+ /** {@inheritDoc} */
+ public Method resolveFunction(String prefix, String localName) {
+
+ return (Method) functions.get(prefix + ":" + localName);
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/MockMethodExpression.java b/shale-test/src/main/java/org/apache/shale/test/el/MockMethodExpression.java
new file mode 100644
index 0000000..ab9e970
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/MockMethodExpression.java
@@ -0,0 +1,237 @@
+/*
+ * 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.shale.test.el;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.MethodExpression;
+import javax.el.MethodInfo;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>MethodExpression</code>.</p>
+ */
+public class MockMethodExpression extends MethodExpression {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 5694105394290316715L;
+
+
+ /**
+ * <p>Construct a new expression for the specified expression string.</p>
+ *
+ * @param expression Expression string to be evaluated
+ * @param signature Parameter signature of the method to be called
+ * @param expectedType Expected type of the result
+ */
+ public MockMethodExpression(String expression, Class[] signature, Class expectedType) {
+
+ if (expression == null) {
+ throw new NullPointerException("Expression string cannot be null");
+ }
+ this.expression = expression;
+ this.signature = signature;
+ this.expectedType = expectedType;
+ parse();
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The parsed elements of this expression.</p>
+ */
+ private String[] elements = null;
+
+
+ /**
+ * <p>The expected result type for <code>getValue()</code> calls.</p>
+ */
+ private Class expectedType = null;
+
+
+ /**
+ * <p>The original expression string used to create this expression.</p>
+ */
+ private String expression = null;
+
+
+ /**
+ * <p>The method signature of the method to be called.</p>
+ */
+ private Class[] signature = null;
+
+
+ // ------------------------------------------------------ Expression Methods
+
+
+ /**
+ * <p>Return <code>true</code> if this expression is equal to the
+ * specified expression.</p>
+ *
+ * @param obj Object to be compared
+ */
+ public boolean equals(Object obj) {
+
+ if ((obj != null) & (obj instanceof MethodExpression)) {
+ return expression.equals(((MethodExpression) obj).getExpressionString());
+ } else {
+ return false;
+ }
+
+ }
+
+
+ /**
+ * <p>Return the original String used to create this expression,
+ * unmodified.</p>
+ */
+ public String getExpressionString() {
+
+ return this.expression;
+
+ }
+
+
+ /**
+ * <p>Return the hash code for this expression.</p>
+ */
+ public int hashCode() {
+
+ return this.expression.hashCode();
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the expression string for this expression
+ * contains only literal text.</p>
+ */
+ public boolean isLiteralText() {
+
+ return (expression.indexOf("${") < 0) && (expression.indexOf("#{") < 0);
+
+ }
+
+
+ // ------------------------------------------------ MethodExpression Methods
+
+
+ /**
+ * <p>Evaluate the expression relative to the specified context,
+ * and return information about the actual implementation method.</p>
+ *
+ * @param context ELContext for this evaluation
+ */
+ public MethodInfo getMethodInfo(ELContext context) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ return new MethodInfo(elements[elements.length - 1], expectedType, signature);
+
+ }
+
+
+ /**
+ * <p>Evaluate the expression relative to the specified ocntext,
+ * and return the result after coercion to the expected result type.</p>
+ *
+ * @param context ELContext for this evaluation
+ * @param params Parameters for this method call
+ */
+ public Object invoke(ELContext context, Object[] params) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ if (isLiteralText()) {
+ return expression;
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ELResolver resolver = fcontext.getApplication().getELResolver();
+ Object base = null;
+ for (int i = 0; i < elements.length - 1; i++) {
+ base = resolver.getValue(context, base, elements[i]);
+ }
+
+ try {
+ Method method = base.getClass().getMethod(elements[elements.length - 1], signature);
+ Object result = method.invoke(base, params);
+ return fcontext.getApplication().getExpressionFactory().coerceToType(result, expectedType);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ELException(e);
+ }
+
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>Parse the expression string into its constituent elemetns.</p>
+ */
+ private void parse() {
+
+ if (isLiteralText()) {
+ elements = new String[0];
+ return;
+ }
+
+ if (expression.startsWith("${") || expression.startsWith("#{")) {
+ if (expression.endsWith("}")) {
+ String temp = expression.substring(2, expression.length() - 1).replaceAll(" ", "");
+ List names = new ArrayList();
+ while (temp.length() > 0) {
+ int period= temp.indexOf(".");
+ if (period >= 0) {
+ names.add(temp.substring(0, period));
+ temp = temp.substring(period + 1);
+ } else {
+ names.add(temp);
+ temp = "";
+ }
+ }
+ elements = (String[]) names.toArray(new String[names.size()]);
+ } else {
+ throw new IllegalArgumentException(expression);
+ }
+ } else {
+ throw new IllegalArgumentException(expression);
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/MockValueExpression.java b/shale-test/src/main/java/org/apache/shale/test/el/MockValueExpression.java
new file mode 100644
index 0000000..641e6f1
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/MockValueExpression.java
@@ -0,0 +1,306 @@
+/*
+ * 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.shale.test.el;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import javax.el.ValueExpression;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>ValueExpression</code>.</p>
+ *
+ * <p>This implementation supports a limited subset of overall expression functionality:</p>
+ * <ul>
+ * <li>A literal string that contains no expression delimiters.</li>
+ * <li>An expression that starts with "#{" or "${", and ends with "}".</li>
+ * </ul>
+ */
+public class MockValueExpression extends ValueExpression {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = -8649071428507512623L;
+
+
+ /**
+ * <p>Construct a new expression for the specified expression string.</p>
+ *
+ * @param expression Expression string to be evaluated
+ * @param expectedType Expected type of the result
+ */
+ public MockValueExpression(String expression, Class expectedType) {
+
+ if (expression == null) {
+ throw new NullPointerException("Expression string cannot be null");
+ }
+ this.expression = expression;
+ this.expectedType = expectedType;
+ parse();
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The parsed elements of this expression.</p>
+ */
+ private String[] elements = null;
+
+
+ /**
+ * <p>The expected result type for <code>getValue()</code> calls.</p>
+ */
+ private Class expectedType = null;
+
+
+ /**
+ * <p>The original expression string used to create this expression.</p>
+ */
+ private String expression = null;
+
+
+ // ------------------------------------------------------ Expression Methods
+
+
+ /**
+ * <p>Return <code>true</code> if this expression is equal to the
+ * specified expression.</p>
+ *
+ * @param obj Object to be compared
+ */
+ public boolean equals(Object obj) {
+
+ if ((obj != null) & (obj instanceof ValueExpression)) {
+ return expression.equals(((ValueExpression) obj).getExpressionString());
+ } else {
+ return false;
+ }
+
+ }
+
+
+ /**
+ * <p>Return the original String used to create this expression,
+ * unmodified.</p>
+ */
+ public String getExpressionString() {
+
+ return this.expression;
+
+ }
+
+
+ /**
+ * <p>Return the hash code for this expression.</p>
+ */
+ public int hashCode() {
+
+ return this.expression.hashCode();
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the expression string for this expression
+ * contains only literal text.</p>
+ */
+ public boolean isLiteralText() {
+
+ return (expression.indexOf("${") < 0) && (expression.indexOf("#{") < 0);
+
+ }
+
+
+ // ------------------------------------------------- ValueExpression Methods
+
+
+ /**
+ * <p>Return the type that the result of this expression will
+ * be coerced to.</p>
+ */
+ public Class getExpectedType() {
+
+ return this.expectedType;
+
+ }
+
+
+ /**
+ * <p>Evaluate this expression relative to the specified context,
+ * and return the most general type that is acceptable for the
+ * value passed in a <code>setValue()</code> call.</p>
+ *
+ * @param context ELContext for this evaluation
+ */
+ public Class getType(ELContext context) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ Object value = getValue(context);
+ if (value == null) {
+ return null;
+ } else {
+ return value.getClass();
+ }
+
+ }
+
+
+ /**
+ * <p>Evaluate this expression relative to the specified context,
+ * and return the result.</p>
+ *
+ * @param context ELContext for this evaluation
+ */
+ public Object getValue(ELContext context) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ if (isLiteralText()) {
+ return expression;
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ELResolver resolver = fcontext.getApplication().getELResolver();
+ Object base = null;
+ for (int i = 0; i < elements.length; i++) {
+ base = resolver.getValue(context, base, elements[i]);
+ }
+ return fcontext.getApplication().getExpressionFactory().coerceToType(base, getExpectedType());
+
+ }
+
+
+ /**
+ * <p>Evaluate this expression relative to the specified context,
+ * and return <code>true</code> if a call to <code>setValue()</code>
+ * will always fail.</p>
+ *
+ * @param context ELContext for this evaluation
+ */
+ public boolean isReadOnly(ELContext context) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ if (isLiteralText()) {
+ return true;
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ELResolver resolver = fcontext.getApplication().getELResolver();
+ Object base = null;
+ for (int i = 0; i < elements.length - 1; i++) {
+ base = resolver.getValue(context, base, elements[i]);
+ }
+ return resolver.isReadOnly(context, base, elements[elements.length - 1]);
+
+ }
+
+
+
+ /**
+ * <p>Evaluate this expression relative to the specified context,
+ * and set the result to the specified value.</p>
+ *
+ * @param context ELContext for this evaluation
+ * @param value Value to which the result should be set
+ */
+ public void setValue(ELContext context, Object value) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ ELResolver resolver = fcontext.getApplication().getELResolver();
+ Object base = null;
+ for (int i = 0; i < elements.length - 1; i++) {
+ base = resolver.getValue(context, base, elements[i]);
+ }
+ resolver.setValue(context, base, elements[elements.length - 1], value);
+
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>Parse the expression string into its constituent elemetns.</p>
+ */
+ private void parse() {
+
+ if (isLiteralText()) {
+ elements = new String[0];
+ return;
+ }
+
+ if (expression.startsWith("${") || expression.startsWith("#{")) {
+ if (expression.endsWith("}")) {
+ List names = new ArrayList();
+ StringBuffer expr = new StringBuffer(expression.substring(2, expression.length() - 1).replaceAll(" ", ""));
+ boolean isBlockOn = false;
+ for (int i = expr.length() - 1; i > -1; i--) {
+ if (expr.charAt(i) == ' ') {
+ expr.deleteCharAt(i);
+ } else if (expr.charAt(i) == ']') {
+ expr.deleteCharAt(i);
+ } else if (expr.charAt(i) == '[') {
+ expr.deleteCharAt(i);
+ } else if (expr.charAt(i) == '\'') {
+ if (!isBlockOn) {
+ expr.deleteCharAt(i);
+ } else {
+ names.add(0, expr.substring(i + 1));
+ expr.delete(i, expr.length());
+ }
+ isBlockOn = !isBlockOn;
+ } else if (expr.charAt(i) == '.' && !isBlockOn) {
+ names.add(0, expr.substring(i + 1));
+ expr.delete(i, expr.length());
+ }
+ }
+ if (expr.length() > 0) {
+ names.add(0, expr.toString());
+ }
+
+ elements = (String[]) names.toArray(new String[names.size()]);
+ } else {
+ throw new IllegalArgumentException(expression);
+ }
+ } else {
+ throw new IllegalArgumentException(expression);
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/MockVariableMapper.java b/shale-test/src/main/java/org/apache/shale/test/el/MockVariableMapper.java
new file mode 100644
index 0000000..2f5c15e
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/MockVariableMapper.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.test.el;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.el.ValueExpression;
+import javax.el.VariableMapper;
+
+/**
+ * <p>Mock implementation of <code>VariableMapper</code>.</p>
+ *
+ * @since 1.0.4
+ */
+
+public class MockVariableMapper extends VariableMapper {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /** Creates a new instance of MockVariableMapper */
+ public MockVariableMapper() {
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>Map of <code>ValueExpression</code>s, keyed by variable name.</p>
+ */
+ private Map expressions = new HashMap();
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // -------------------------------------------------- FunctionMapper Methods
+
+
+ /** {@inheritDoc} */
+ public ValueExpression resolveVariable(String variable) {
+
+ return (ValueExpression) expressions.get(variable);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ValueExpression setVariable(String variable, ValueExpression expression) {
+
+ ValueExpression original = (ValueExpression) expressions.get(variable);
+ if (expression == null) {
+ expressions.remove(variable);
+ } else {
+ expressions.put(variable, expression);
+ }
+ return original;
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/MockVariableValueExpression.java b/shale-test/src/main/java/org/apache/shale/test/el/MockVariableValueExpression.java
new file mode 100644
index 0000000..dd4e17f
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/MockVariableValueExpression.java
@@ -0,0 +1,208 @@
+/*
+ * 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.shale.test.el;
+
+import javax.el.ELContext;
+import javax.el.PropertyNotWritableException;
+import javax.el.ValueExpression;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>ValueExpression</code> that wraps a variable.</p>
+ */
+public class MockVariableValueExpression extends ValueExpression {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 4475919948345298291L;
+
+
+ /**
+ * <p>Construct a new expression for the specified instance.</p>
+ *
+ * @param instance Variable instance to be wrapped
+ * @param expectedType Expected type of the result
+ */
+ public MockVariableValueExpression(Object instance, Class expectedType) {
+
+ if (instance == null) {
+ throw new NullPointerException("Instance cannot be null");
+ }
+ this.instance = instance;
+ this.expectedType = expectedType;
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The expected result type for <code>getValue()</code> calls.</p>
+ */
+ private Class expectedType = null;
+
+
+ /**
+ * <p>The variable instance being wrapped by this expression.</p>
+ */
+ private Object instance = null;
+
+
+ // ------------------------------------------------------ Expression Methods
+
+
+ /**
+ * <p>Return <code>true</code> if this expression is equal to the
+ * specified expression.</p>
+ *
+ * @param obj Object to be compared
+ */
+ public boolean equals(Object obj) {
+
+ if ((obj != null) & (obj instanceof ValueExpression)) {
+ return instance.toString().equals(((ValueExpression) obj).getExpressionString());
+ } else {
+ return false;
+ }
+
+ }
+
+
+ /**
+ * <p>Return the original String used to create this expression,
+ * unmodified.</p>
+ */
+ public String getExpressionString() {
+
+ return this.instance.toString();
+
+ }
+
+
+ /**
+ * <p>Return the hash code for this expression.</p>
+ */
+ public int hashCode() {
+
+ return this.instance.toString().hashCode();
+
+ }
+
+
+ /**
+ * <p>Return <code>true</code> if the expression string for this expression
+ * contains only literal text.</p>
+ */
+ public boolean isLiteralText() {
+
+ return true;
+
+ }
+
+
+ // ------------------------------------------------- ValueExpression Methods
+
+
+ /**
+ * <p>Return the type that the result of this expression will
+ * be coerced to.</p>
+ */
+ public Class getExpectedType() {
+
+ return this.expectedType;
+
+ }
+
+
+ /**
+ * <p>Evaluate this expression relative to the specified context,
+ * and return the most general type that is acceptable for the
+ * value passed in a <code>setValue()</code> call.</p>
+ *
+ * @param context ELContext for this evaluation
+ */
+ public Class getType(ELContext context) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ return this.instance.getClass();
+
+ }
+
+
+ /**
+ * <p>Evaluate this expression relative to the specified context,
+ * and return the result.</p>
+ *
+ * @param context ELContext for this evaluation
+ */
+ public Object getValue(ELContext context) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ FacesContext fcontext = (FacesContext) context.getContext(FacesContext.class);
+ return fcontext.getApplication().getExpressionFactory().coerceToType(instance, expectedType);
+
+ }
+
+
+ /**
+ * <p>Evaluate this expression relative to the specified context,
+ * and return <code>true</code> if a call to <code>setValue()</code>
+ * will always fail.</p>
+ *
+ * @param context ELContext for this evaluation
+ */
+ public boolean isReadOnly(ELContext context) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ return true;
+
+ }
+
+
+
+ /**
+ * <p>Evaluate this expression relative to the specified context,
+ * and set the result to the specified value.</p>
+ *
+ * @param context ELContext for this evaluation
+ * @param value Value to which the result should be set
+ */
+ public void setValue(ELContext context, Object value) {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+
+ throw new PropertyNotWritableException();
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/el/package.html b/shale-test/src/main/java/org/apache/shale/test/el/package.html
new file mode 100644
index 0000000..f539ed5
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/el/package.html
@@ -0,0 +1,21 @@
+<body>
+<!--
+ 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.
+-->
+ <p>This package contains mock objects and supporting infrastructure
+ for expression evaluation using the Unified EL APIs. These classes
+ are only relevant when running in a JSF 1.2 environment.</p>
+</body>
\ No newline at end of file
diff --git a/shale-test/src/main/java/org/apache/shale/test/htmlunit/AbstractHtmlUnitTestCase.java b/shale-test/src/main/java/org/apache/shale/test/htmlunit/AbstractHtmlUnitTestCase.java
new file mode 100644
index 0000000..b4f8435
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/htmlunit/AbstractHtmlUnitTestCase.java
@@ -0,0 +1,330 @@
+/*
+ * 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.shale.test.htmlunit;
+
+import com.gargoylesoftware.htmlunit.ElementNotFoundException;
+import com.gargoylesoftware.htmlunit.WebClient;
+import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
+import com.gargoylesoftware.htmlunit.html.HtmlBody;
+import com.gargoylesoftware.htmlunit.html.HtmlElement;
+import com.gargoylesoftware.htmlunit.html.HtmlForm;
+import com.gargoylesoftware.htmlunit.html.HtmlHead;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Iterator;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+
+/**
+ * <p>Abstract base class for system integration tests based on HtmlUnit.
+ * These tests will expect a system property named <code>url</code> to be
+ * present, which will define the URL (including the context path, but
+ * without a trailing slash) of the application to be tested.</p>
+ */
+
+public abstract class AbstractHtmlUnitTestCase extends TestCase {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a new instance of this test case.</p>
+ *
+ * @param name Name of the new test case
+ */
+ public AbstractHtmlUnitTestCase(String name) {
+
+ super(name);
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The most recently retrieved page from the server.</p>
+ */
+ protected HtmlPage page = null;
+
+
+ /**
+ * <p>The calculated URL for the installed "systest" web application.
+ * This value is based on a system property named <code>url</code>,
+ * which must be defined as part of the command line that executes
+ * each test case.</p>
+ */
+ protected URL url = null;
+
+
+ /**
+ * <p>The web client for this test case.</p>
+ */
+ protected WebClient webClient = null;
+
+
+ // ------------------------------------------------------ Test Setup Methods
+
+
+ /**
+ * <p>Set up the instance variables required for this test case.</p>
+ *
+ * @exception Exception if an error occurs
+ */
+ protected void setUp() throws Exception {
+
+ // Calculate the URL for the installed "systest" web application
+ String url = System.getProperty("url");
+ this.url = new URL(url + "/");
+
+ // Initialize HtmlUnit constructs for this test case
+ webClient = new WebClient();
+
+ }
+
+
+ /**
+ * <p>Return the set of tests included in this test suite.</p>
+ */
+ public static Test suite() {
+
+ return (new TestSuite(AbstractHtmlUnitTestCase.class));
+
+ }
+
+
+ /**
+ * <p>Tear down instance variables required by this test case.</p>
+ */
+ protected void tearDown() throws Exception {
+
+ page = null;
+ url = null;
+ webClient = null;
+
+ }
+
+
+
+ // ------------------------------------------------------- Protected Methods
+
+
+ /**
+ * <p>Return the body element for the most recently retrieved page.
+ * If there is no such element, return <code>null</code>.</p>
+ *
+ * @exception Exception if an error occurs
+ */
+ protected HtmlBody body() throws Exception {
+
+ Iterator elements = page.getAllHtmlChildElements();
+ while (elements.hasNext()) {
+ HtmlElement element = (HtmlElement) elements.next();
+ if (element instanceof HtmlBody) {
+ return ((HtmlBody) element);
+ }
+ }
+ return (null);
+
+ }
+
+
+ /**
+ * <p>Return the HTML element with the specified <code>id</code> from the
+ * most recently retrieved page. If there is no such element, return
+ * <code>null</code>.</p>
+ *
+ * @param id Identifier of the requested element.
+ *
+ * @exception Exception if an error occurs
+ */
+ protected HtmlElement element(String id) throws Exception {
+
+ try {
+ return (page.getHtmlElementById(id));
+ } catch (ElementNotFoundException e) {
+ return (null);
+ }
+
+ }
+
+
+ /**
+ * <p>Return the form with the specified <code>id</code> from the most
+ * recently retrieved page. If there is no such form, return
+ * <code>null</code>.<p>
+ *
+ * @param id Identifier of the requested form.
+ *
+ * @exception Exception if an error occurs
+ */
+ protected HtmlForm form(String id) throws Exception {
+
+ Iterator forms = page.getForms().iterator();
+ while (forms.hasNext()) {
+ HtmlForm form = (HtmlForm) forms.next();
+ if (id.equals(form.getAttributeValue("id"))) {
+ return (form);
+ }
+ }
+ return (null);
+
+ }
+
+
+ /**
+ * <p>Return the head element for the most recently retrieved page.
+ * If there is no such element, return <code>null</code>.</p>
+ *
+ * @exception Exception if an error occurs
+ */
+ protected HtmlHead head() throws Exception {
+
+ Iterator elements = page.getAllHtmlChildElements();
+ while (elements.hasNext()) {
+ HtmlElement element = (HtmlElement) elements.next();
+ if (element instanceof HtmlHead) {
+ return ((HtmlHead) element);
+ }
+ }
+ return (null);
+
+ }
+
+
+ /**
+ * <p>Click the specified hyperlink, and retrieve the subsequent page,
+ * saving a reference so that other utility methods may be used to
+ * retrieve information from it.</p>
+ *
+ * @param anchor Anchor component to click
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ protected HtmlPage link(HtmlAnchor anchor) throws IOException {
+
+ HtmlPage page = (HtmlPage) anchor.click();
+ this.page = page;
+ return page;
+
+ }
+
+
+ /**
+ * <p>Return the currently stored page reference.</p>
+ */
+ protected HtmlPage page() {
+
+ return this.page;
+
+ }
+
+
+ /**
+ * <p>Retrieve and return the page at the specified context relative path.
+ * Save a reference to this page so that other utility methods may be used
+ * to retrieve information from it.</p>
+ *
+ * @param path Context relative path
+ *
+ * @exception IllegalArgumentException if the context relative path
+ * does not begin with a '/' character
+ * @exception Exception if a different error occurs
+ */
+ protected HtmlPage page(String path) throws Exception {
+
+ HtmlPage page = (HtmlPage) webClient.getPage(url(path));
+ this.page = page;
+ return (page);
+
+ }
+
+
+ /**
+ * <p>Reset the stored page reference to the specified value. This is
+ * useful for scenarios testing resubmit of the same page (simulating the
+ * user pressing the back button and then submitting again).</p>
+ *
+ * @param page Previously saved page to which to reset
+ */
+ protected void reset(HtmlPage page) {
+
+ this.page = page;
+
+ }
+
+
+ /**
+ * <p>Submit the current page, using the specified component, and retrieve
+ * the subsequent page, saving a reference so that other utility methods
+ * may be used to retrieve information from it.</p>
+ *
+ * @param submit Submit button component to click
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ protected HtmlPage submit(HtmlSubmitInput submit) throws IOException {
+
+ HtmlPage page = (HtmlPage) submit.click();
+ this.page = page;
+ return page;
+
+ }
+
+
+ /**
+ * <p>Return the page title from the most recently retrieved page.
+ * Any leading and trailing whitespace will be trimmed.</p>
+ *
+ * @exception Exception if an error occurs
+ */
+ protected String title() throws Exception {
+
+ return (page.getTitleText().trim());
+
+ }
+
+
+ /**
+ * <p>Calculate and return an absolute URL for the specified context
+ * relative path, which must begin with a '/' character.</p>
+ *
+ * @param path Context relative path
+ *
+ * @exception IllegalArgumentException if the context relative path
+ * does not begin with a '/' character
+ * @exception Exception if a different error ocurs
+ */
+ protected URL url(String path) throws Exception {
+
+ if (path.charAt(0) != '/') {
+ throw new IllegalArgumentException("Context path '" + path
+ + "' does not start with '/'");
+ }
+ return new URL(url, path.substring(1));
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/jmock/AbstractJmockJsfTestCase.java b/shale-test/src/main/java/org/apache/shale/test/jmock/AbstractJmockJsfTestCase.java
new file mode 100644
index 0000000..0e91c31
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/jmock/AbstractJmockJsfTestCase.java
@@ -0,0 +1,188 @@
+/*
+ * 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.shale.test.jmock;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.ApplicationFactory;
+import javax.faces.component.UIViewRoot;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.RenderKitFactory;
+
+import org.apache.shale.test.mock.MockApplication;
+import org.apache.shale.test.mock.MockExternalContext;
+import org.apache.shale.test.mock.MockFacesContext;
+import org.apache.shale.test.mock.MockFacesContextFactory;
+import org.apache.shale.test.mock.MockHttpServletRequest;
+import org.apache.shale.test.mock.MockHttpServletResponse;
+import org.apache.shale.test.mock.MockHttpSession;
+import org.apache.shale.test.mock.MockRenderKit;
+import org.apache.shale.test.mock.MockServletConfig;
+import org.apache.shale.test.mock.MockServletContext;
+import org.apache.shale.test.mock.lifecycle.MockLifecycle;
+import org.apache.shale.test.mock.lifecycle.MockLifecycleFactory;
+import org.jmock.cglib.MockObjectTestCase;
+
+/**
+ * <p>Abstract JMock test case base class, which sets up the JavaServer Faces
+ * mock object environment for a particular simulated request. The following
+ * protected variables are initialized in the <code>setUp()</code> method, and
+ * cleaned up in the <code>tearDown()</code> method:</p>
+ * <ul>
+ * <li><code>application</code> (<code>MockApplication</code>)</li>
+ * <li><code>config</code> (<code>MockServletConfig</code>)</li>
+ * <li><code>externalContext</code> (<code>MockExternalContext</code>)</li>
+ * <li><code>facesContext</code> (<code>MockFacesContext</code>)</li>
+ * <li><code>lifecycle</code> (<code>MockLifecycle</code>)</li>
+ * <li><code>request</code> (<code>MockHttpServletRequest</code></li>
+ * <li><code>response</code> (<code>MockHttpServletResponse</code>)</li>
+ * <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+ * <li><code>session</code> (<code>MockHttpSession</code>)</li>
+ * </ul>
+ *
+ * <p>In addition, appropriate factory classes will have been registered with
+ * <code>javax.faces.FactoryFinder</code> for <code>Application</code> and
+ * <code>RenderKit</code> instances. The created <code>FacesContext</code>
+ * instance will also have been registered in the apppriate thread local
+ * variable, to simulate what a servlet container would do.</p>
+ *
+ * <p><strong>WARNING</strong> - If you choose to subclass this class, be sure
+ * your <code>setUp()</code> and <code>tearDown()</code> methods call
+ * <code>super.setUp()</code> and <code>super.tearDown()</code> respectively,
+ * and that you implement your own <code>suite()</code> method that exposes
+ * the test methods for your test case.</p>
+ */
+
+public abstract class AbstractJmockJsfTestCase extends MockObjectTestCase {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ // Construct a new instance of this test case.
+ public AbstractJmockJsfTestCase(String name) {
+ setName(name);
+ }
+
+
+ // ---------------------------------------------------- Overall Test Methods
+
+
+ // Set up instance variables required by this test case.
+ protected void setUp() throws Exception {
+
+ // Set up a new thread context class loader
+ threadContextClassLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(new URLClassLoader(new URL[0],
+ this.getClass().getClassLoader()));
+
+ // Set up Servlet API Objects
+ servletContext = new MockServletContext();
+ config = new MockServletConfig(servletContext);
+ session = new MockHttpSession();
+ session.setServletContext(servletContext);
+ request = new MockHttpServletRequest(session);
+ request.setServletContext(servletContext);
+ response = new MockHttpServletResponse();
+
+ // Set up JSF API Objects
+ FactoryFinder.releaseFactories();
+ FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
+ "org.apache.shale.test.mock.MockApplicationFactory");
+ FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY,
+ "org.apache.shale.test.mock.MockFacesContextFactory");
+ FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY,
+ "org.apache.shale.test.mock.lifecycle.MockLifecycleFactory");
+ FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
+ "org.apache.shale.test.mock.MockRenderKitFactory");
+
+ externalContext =
+ new MockExternalContext(servletContext, request, response);
+ lifecycleFactory = (MockLifecycleFactory)
+ FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+ lifecycle = (MockLifecycle)
+ lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
+ facesContextFactory = (MockFacesContextFactory)
+ FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+ facesContext = (MockFacesContext)
+ facesContextFactory.getFacesContext(servletContext,
+ request,
+ response,
+ lifecycle);
+ externalContext = (MockExternalContext) facesContext.getExternalContext();
+ UIViewRoot root = new UIViewRoot();
+ root.setViewId("/viewId");
+ root.setRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+ facesContext.setViewRoot(root);
+ ApplicationFactory applicationFactory = (ApplicationFactory)
+ FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
+ application = (MockApplication) applicationFactory.getApplication();
+ facesContext.setApplication(application);
+ RenderKitFactory renderKitFactory = (RenderKitFactory)
+ FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ renderKit = new MockRenderKit();
+ renderKitFactory.addRenderKit(RenderKitFactory.HTML_BASIC_RENDER_KIT, renderKit);
+
+ }
+
+ // Tear down instance variables required by this test case.
+ protected void tearDown() throws Exception {
+
+ application = null;
+ config = null;
+ externalContext = null;
+ facesContext.release();
+ facesContext = null;
+ lifecycle = null;
+ lifecycleFactory = null;
+ renderKit = null;
+ request = null;
+ response = null;
+ servletContext = null;
+ session = null;
+ FactoryFinder.releaseFactories();
+
+ Thread.currentThread().setContextClassLoader(threadContextClassLoader);
+ threadContextClassLoader = null;
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ // Mock object instances for our tests
+ protected MockApplication application = null;
+ protected MockServletConfig config = null;
+ protected MockExternalContext externalContext = null;
+ protected MockFacesContext facesContext = null;
+ protected MockFacesContextFactory facesContextFactory = null;
+ protected MockLifecycle lifecycle = null;
+ protected MockLifecycleFactory lifecycleFactory = null;
+ protected MockRenderKit renderKit = null;
+ protected MockHttpServletRequest request = null;
+ protected MockHttpServletResponse response = null;
+ protected MockServletContext servletContext = null;
+ protected MockHttpSession session = null;
+
+ // Thread context class loader saved and restored after each test
+ private ClassLoader threadContextClassLoader = null;
+
+}
\ No newline at end of file
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockActionListener.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockActionListener.java
new file mode 100644
index 0000000..02e8197
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockActionListener.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.test.mock;
+
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.ActionEvent;
+import javax.faces.event.ActionListener;
+
+/**
+ * <p>Mock implementation of the default <code>ActionListener</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockActionListener implements ActionListener {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a default instance.</p>
+ */
+ public MockActionListener() {
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ // -------------------------------------------------- ActionListener Methods
+
+
+ /**
+ * <p>Process the specified <code>ActionEvent</code>.</p>
+ *
+ * @param event Event to be processed
+ *
+ * @exception AbortProcessingException if further event firing
+ * should be skipped
+ */
+ public void processAction(ActionEvent event) throws AbortProcessingException {
+ // FIXME - provide default implementation
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockApplication.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockApplication.java
new file mode 100644
index 0000000..b112ab7
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockApplication.java
@@ -0,0 +1,463 @@
+/*
+ * 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.shale.test.mock;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.faces.FacesException;
+import javax.faces.application.Application;
+import javax.faces.application.NavigationHandler;
+import javax.faces.application.StateManager;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+import javax.faces.el.MethodBinding;
+import javax.faces.el.PropertyResolver;
+import javax.faces.el.ValueBinding;
+import javax.faces.el.VariableResolver;
+import javax.faces.event.ActionListener;
+import javax.faces.render.RenderKitFactory;
+import javax.faces.validator.Validator;
+
+/**
+ * <p>Mock implementation of <code>Application</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockApplication extends Application {
+
+
+ // ------------------------------------------------------------ Constructors
+
+ /**
+ * <p>Construct a default instance.</p>
+ */
+ public MockApplication() {
+
+ setActionListener(new MockActionListener());
+ components = new HashMap();
+ converters = new HashMap();
+ converters1 = new HashMap();
+ setDefaultLocale(Locale.getDefault());
+ setDefaultRenderKitId(RenderKitFactory.HTML_BASIC_RENDER_KIT);
+ setNavigationHandler(new MockNavigationHandler());
+ setPropertyResolver(new MockPropertyResolver());
+ setStateManager(new MockStateManager());
+ setSupportedLocales(new ArrayList());
+ validators = new HashMap();
+ setVariableResolver(new MockVariableResolver());
+ setViewHandler(new MockViewHandler());
+
+ // Register the standard by-id converters
+ addConverter("javax.faces.BigDecimal", "javax.faces.convert.BigDecimalConverter");
+ addConverter("javax.faces.BigInteger", "javax.faces.convert.BigIntegerConverter");
+ addConverter("javax.faces.Boolean", "javax.faces.convert.BooleanConverter");
+ addConverter("javax.faces.Byte", "javax.faces.convert.ByteConverter");
+ addConverter("javax.faces.Character", "javax.faces.convert.CharacterConverter");
+ addConverter("javax.faces.DateTime", "javax.faces.convert.DateTimeConverter");
+ addConverter("javax.faces.Double", "javax.faces.convert.DoubleConverter");
+ addConverter("javax.faces.Float", "javax.faces.convert.FloatConverter");
+ addConverter("javax.faces.Integer", "javax.faces.Convert.IntegerConverter");
+ addConverter("javax.faces.Long", "javax.faces.convert.LongConverter");
+ addConverter("javax.faces.Number", "javax.faces.convert.NumberConverter");
+ addConverter("javax.faces.Short", "javax.faces.convert.ShortConverter");
+
+ // Register the standard by-type converters
+ addConverter(Boolean.class, "javax.faces.convert.BooleanConverter");
+ addConverter(Boolean.TYPE, "javax.faces.convert.BooleanConverter");
+ addConverter(Byte.class, "javax.faces.convert.ByteConverter");
+ addConverter(Byte.TYPE, "javax.faces.convert.ByteConverter");
+ addConverter(Character.class, "javax.faces.convert.CharacterConverter");
+ addConverter(Character.TYPE, "javax.faces.convert.CharacterConverter");
+ addConverter(Double.class, "javax.faces.convert.DoubleConverter");
+ addConverter(Double.TYPE, "javax.faces.convert.DoubleConverter");
+ addConverter(Float.class, "javax.faces.convert.FloatConverter");
+ addConverter(Float.TYPE, "javax.faces.convert.FloatConverter");
+ addConverter(Integer.class, "javax.faces.convert.IntegerConverter");
+ addConverter(Integer.TYPE, "javax.faces.convert.IntegerConverter");
+ addConverter(Long.class, "javax.faces.convert.LongConverter");
+ addConverter(Long.TYPE, "javax.faces.convert.LongConverter");
+ addConverter(Short.class, "javax.faces.convert.ShortConverter");
+ addConverter(Short.TYPE, "javax.faces.convert.ShortConverter");
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private ActionListener actionListener = null;
+ private Map components = null;
+ private Map converters = null; // By id
+ private Map converters1 = null; // By type
+ private Locale defaultLocale = null;
+ private String defaultRenderKitId = null;
+ private String messageBundle = null;
+ private NavigationHandler navigationHandler = null;
+ private PropertyResolver propertyResolver = null;
+ private StateManager stateManager = null;
+ private Collection supportedLocales = null;
+ private Map validators = null;
+ private VariableResolver variableResolver = null;
+ private ViewHandler viewHandler = null;
+
+
+ // ----------------------------------------------------- Application Methods
+
+
+ /** {@inheritDoc} */
+ public ActionListener getActionListener() {
+
+ return this.actionListener;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setActionListener(ActionListener actionListener) {
+ this.actionListener = actionListener;
+ }
+
+
+ /** {@inheritDoc} */
+ public Locale getDefaultLocale() {
+
+ return this.defaultLocale;
+
+ }
+
+ /** {@inheritDoc} */
+ public void setDefaultLocale(Locale defaultLocale) {
+
+ this.defaultLocale = defaultLocale;
+
+ }
+
+ /** {@inheritDoc} */
+ public String getDefaultRenderKitId() {
+
+ return this.defaultRenderKitId;
+
+ }
+
+ /** {@inheritDoc} */
+ public void setDefaultRenderKitId(String defaultRenderKitId) {
+
+ this.defaultRenderKitId = defaultRenderKitId;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getMessageBundle() {
+
+ return this.messageBundle;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setMessageBundle(String messageBundle) {
+
+ this.messageBundle = messageBundle;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public NavigationHandler getNavigationHandler() {
+
+ return this.navigationHandler;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setNavigationHandler(NavigationHandler navigationHandler) {
+
+ this.navigationHandler = navigationHandler;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public PropertyResolver getPropertyResolver() {
+
+ return this.propertyResolver;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setPropertyResolver(PropertyResolver propertyResolver) {
+
+ this.propertyResolver = propertyResolver;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public StateManager getStateManager() {
+
+ return this.stateManager;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setStateManager(StateManager stateManager) {
+
+ this.stateManager = stateManager;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getSupportedLocales() {
+
+ return this.supportedLocales.iterator();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setSupportedLocales(Collection supportedLocales) {
+
+ this.supportedLocales = supportedLocales;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public VariableResolver getVariableResolver() {
+
+ return this.variableResolver;
+ }
+
+
+ /** {@inheritDoc} */
+ public void setVariableResolver(VariableResolver variableResolver) {
+
+ this.variableResolver = variableResolver;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ViewHandler getViewHandler() {
+
+ return this.viewHandler;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setViewHandler(ViewHandler viewHandler) {
+
+ this.viewHandler = viewHandler;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addComponent(String componentType, String componentClass) {
+
+ components.put(componentType, componentClass);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public UIComponent createComponent(String componentType) {
+
+ if (componentType == null) {
+ throw new NullPointerException("Requested component type is null");
+ }
+ String componentClass = (String) components.get(componentType);
+ if (componentClass == null) {
+ throw new FacesException("No component class registered for component type '"
+ + componentType + "'");
+ }
+ try {
+ Class clazz = Class.forName(componentClass);
+ return ((UIComponent) clazz.newInstance());
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public UIComponent createComponent(ValueBinding componentBinding,
+ FacesContext context,
+ String componentType)
+ throws FacesException {
+
+ UIComponent component = null;
+ try {
+ component = (UIComponent) componentBinding.getValue(context);
+ if (component == null) {
+ component = createComponent(componentType);
+ componentBinding.setValue(context, component);
+ }
+
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+ return component;
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getComponentTypes() {
+
+ return (components.keySet().iterator());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addConverter(String converterId, String converterClass) {
+
+ converters.put(converterId, converterClass);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addConverter(Class targetClass, String converterClass) {
+
+ converters1.put(targetClass, converterClass);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Converter createConverter(String converterId) {
+
+ String converterClass = (String) converters.get(converterId);
+ if (converterClass == null) {
+ return null;
+ }
+ try {
+ Class clazz = Class.forName(converterClass);
+ return ((Converter) clazz.newInstance());
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Converter createConverter(Class targetClass) {
+
+ String converterClass = (String) converters1.get(targetClass);
+ if (converterClass == null) {
+ return null;
+ }
+ try {
+ Class clazz = Class.forName(converterClass);
+ return ((Converter) clazz.newInstance());
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getConverterIds() {
+
+ return (converters.keySet().iterator());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getConverterTypes() {
+
+ return (converters1.keySet().iterator());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public MethodBinding createMethodBinding(String ref, Class[] params) {
+
+ if (ref == null) {
+ throw new NullPointerException();
+ } else {
+ return (new MockMethodBinding(this, ref, params));
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ValueBinding createValueBinding(String ref) {
+
+ if (ref == null) {
+ throw new NullPointerException();
+ } else {
+ return (new MockValueBinding(this, ref));
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addValidator(String validatorId, String validatorClass) {
+
+ validators.put(validatorId, validatorClass);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Validator createValidator(String validatorId) {
+
+ String validatorClass = (String) validators.get(validatorId);
+ try {
+ Class clazz = Class.forName(validatorClass);
+ return ((Validator) clazz.newInstance());
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getValidatorIds() {
+ return (validators.keySet().iterator());
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockApplication12.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockApplication12.java
new file mode 100644
index 0000000..9099b24
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockApplication12.java
@@ -0,0 +1,274 @@
+/*
+ * 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.shale.test.mock;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+import javax.el.ArrayELResolver;
+import javax.el.BeanELResolver;
+import javax.el.CompositeELResolver;
+import javax.el.ELContextListener;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.ExpressionFactory;
+import javax.el.ListELResolver;
+import javax.el.MapELResolver;
+import javax.el.ResourceBundleELResolver;
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import org.apache.shale.test.el.FacesImplicitObjectELResolver;
+import org.apache.shale.test.el.FacesPropertyResolverChainWrapper;
+import org.apache.shale.test.el.FacesResourceBundleELResolver;
+import org.apache.shale.test.el.FacesScopedAttributeELResolver;
+import org.apache.shale.test.el.FacesVariableResolverChainWrapper;
+import org.apache.shale.test.el.MockExpressionFactory;
+
+/**
+ * <p>Mock implementation of <code>ExternalContext</code> that includes the semantics
+ * added by JavaServer Faces 1.2.</p>
+ *
+ * $Id$
+ *
+ * @since 1.0.4
+ */
+public class MockApplication12 extends MockApplication {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a default instance.</p>
+ */
+ public MockApplication12() {
+
+ super();
+
+ // Configure our expression factory and EL resolvers
+ expressionFactory = new MockExpressionFactory();
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>A list of resource bundles configured for this application.</p>
+ */
+ private Map bundles = new HashMap();
+
+
+ /**
+ * <p>The set of configured ELContextListener instances.</p>
+ */
+ private List elContextListeners = new ArrayList();
+
+
+ /**
+ * <p>Expression factory for this instance.</p>
+ */
+ private ExpressionFactory expressionFactory = null;
+
+
+ /**
+ * <p>The configured composite resolver to be returned by <code>getELResolver()</code>.
+ * This value is lazily instantiated.</p>
+ */
+ private ELResolver resolver = null;
+
+
+ /**
+ * <p>The set of ELResolver instances configured on this instance.</p>
+ */
+ private List resolvers = new ArrayList();
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ /**
+ * <p>Add the specified resource bundle to those associated with
+ * this application.</p>
+ *
+ * @param name Name under which to add this resource bundle
+ * @param bundle ResourceBundle to add
+ */
+ public void addResourceBundle(String name, ResourceBundle bundle) {
+ bundles.put(name, bundle);
+ }
+
+
+ /**
+ * <p>Return a <code>Map</code> of the resource bundles configured
+ * for this application, keyed by name.</p>
+ */
+ public Map getResourceBundles() {
+ return bundles;
+ }
+
+
+ // ----------------------------------------------------- Application Methods
+
+
+ /** {@inheritDoc} */
+ public void addELContextListener(ELContextListener listener) {
+
+ elContextListeners.add(listener);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addELResolver(ELResolver resolver) {
+
+ // Simulate the restriction that you cannot add resolvers after
+ // the first request has been processed.
+ if (this.resolver != null) {
+ throw new IllegalStateException("Cannot add resolvers now");
+ }
+
+ resolvers.add(resolver);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public UIComponent createComponent(ValueExpression expression,
+ FacesContext context,
+ String componentType) {
+
+ UIComponent component = null;
+ try {
+ component = (UIComponent) expression.getValue(context.getELContext());
+ if (component == null) {
+ component = createComponent(componentType);
+ expression.setValue(context.getELContext(), component);
+ }
+
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+ return component;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object evaluateExpressionGet(FacesContext context,
+ String expression,
+ Class expectedType) throws ELException {
+
+ ValueExpression ve = getExpressionFactory().createValueExpression
+ (context.getELContext(), expression, expectedType);
+ return ve.getValue(context.getELContext());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ELContextListener[] getELContextListeners() {
+
+ return (ELContextListener[])
+ elContextListeners.toArray(new ELContextListener[elContextListeners.size()]);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ELResolver getELResolver() {
+
+ if (resolver == null) {
+
+ // Configure a default ELResolver per Section 5.6.2 of JSF 1.2
+ CompositeELResolver composite = new CompositeELResolver();
+
+ composite.add(new FacesImplicitObjectELResolver());
+
+ CompositeELResolver nested = new CompositeELResolver();
+ // FIXME - nested.add() "ELResolvers from application configuration resources"
+ nested.add(new FacesVariableResolverChainWrapper());
+ nested.add(new FacesPropertyResolverChainWrapper());
+ Iterator items = resolvers.iterator();
+ while (items.hasNext()) {
+ nested.add((ELResolver) items.next());
+ }
+ composite.add(nested);
+
+ // composite.add(new faces.ManagedBeanELResolver()); // FIXME
+ composite.add(new ResourceBundleELResolver());
+ composite.add(new FacesResourceBundleELResolver());
+ composite.add(new MapELResolver());
+ composite.add(new ListELResolver());
+ composite.add(new ArrayELResolver());
+ composite.add(new BeanELResolver());
+ composite.add(new FacesScopedAttributeELResolver());
+
+ // Make the resolver we have configured the application wide one
+ resolver = composite;
+
+ }
+ return resolver;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ExpressionFactory getExpressionFactory() {
+
+ return this.expressionFactory;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ResourceBundle getResourceBundle(FacesContext context, String name) {
+
+ if ((context == null) || (name == null)) {
+ throw new NullPointerException();
+ }
+ Locale locale = null;
+ UIViewRoot viewRoot = context.getViewRoot();
+ if (viewRoot != null) {
+ locale = viewRoot.getLocale();
+ }
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ return ResourceBundle.getBundle(name, locale);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void removeELContextListener(ELContextListener listener) {
+
+ elContextListeners.remove(listener);
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockApplicationFactory.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockApplicationFactory.java
new file mode 100644
index 0000000..e8dba9e
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockApplicationFactory.java
@@ -0,0 +1,103 @@
+/*
+ * 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.shale.test.mock;
+
+import javax.faces.FacesException;
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+
+/**
+ * <p>Mock implementation of <code>ApplicationFactory</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockApplicationFactory extends ApplicationFactory {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a default instance.</p>
+ */
+ public MockApplicationFactory() {
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The <code>Application</code> instance to be returned by
+ * this factory.</p>
+ */
+ private Application application = null;
+
+
+ // --------------------------------------------- AppolicationFactory Methods
+
+
+ /** {@inheritDoc} */
+ public Application getApplication() {
+
+ if (this.application == null) {
+ Class clazz = null;
+ try {
+ clazz = this.getClass().getClassLoader().loadClass
+ ("org.apache.shale.test.mock.MockApplication12");
+ this.application = (MockApplication) clazz.newInstance();
+ } catch (NoClassDefFoundError e) {
+ clazz = null; // We are not running in a JSF 1.2 environment
+ } catch (ClassNotFoundException e) {
+ clazz = null; // Same as above
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+ if (clazz == null) {
+ try {
+ clazz = this.getClass().getClassLoader().loadClass
+ ("org.apache.shale.test.mock.MockApplication");
+ this.application = (MockApplication) clazz.newInstance();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+ }
+ }
+ return this.application;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setApplication(Application application) {
+
+ this.application = application;
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockApplicationMap.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockApplicationMap.java
new file mode 100644
index 0000000..9db19e1
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockApplicationMap.java
@@ -0,0 +1,248 @@
+/*
+ * 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.shale.test.mock;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+
+/**
+ * <p>Mock impementation of <code>Map</code> for the application scope
+ * attributes managed by {@link MockExternalContext}.</p>
+ *
+ * $Id$
+ */
+
+class MockApplicationMap implements Map {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a default instance.</p>
+ *
+ * @param context ServletContext whose attributes we are wrapping
+ */
+ public MockApplicationMap(ServletContext context) {
+
+ this.context = context;
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The <code>ServletContext</code> instance we are wrapping.</p>
+ */
+ private ServletContext context = null;
+
+
+ // ------------------------------------------------------------- Map Methods
+
+
+ /** {@inheritDoc} */
+ public void clear() {
+
+ Iterator keys = keySet().iterator();
+ while (keys.hasNext()) {
+ context.removeAttribute((String) keys.next());
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean containsKey(Object key) {
+
+ return context.getAttribute(key(key)) != null;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean containsValue(Object value) {
+
+ if (value == null) {
+ return false;
+ }
+ Enumeration keys = context.getAttributeNames();
+ while (keys.hasMoreElements()) {
+ Object next = context.getAttribute((String) keys.nextElement());
+ if (next == value) {
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Set entrySet() {
+
+ Set set = new HashSet();
+ Enumeration keys = context.getAttributeNames();
+ while (keys.hasMoreElements()) {
+ set.add(context.getAttribute((String) keys.nextElement()));
+ }
+ return set;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean equals(Object o) {
+
+ return context.equals(o);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object get(Object key) {
+
+ return context.getAttribute(key(key));
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int hashCode() {
+
+ return context.hashCode();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isEmpty() {
+
+ return size() < 1;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Set keySet() {
+
+ Set set = new HashSet();
+ Enumeration keys = context.getAttributeNames();
+ while (keys.hasMoreElements()) {
+ set.add(keys.nextElement());
+ }
+ return set;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object put(Object key, Object value) {
+
+ if (value == null) {
+ return remove(key);
+ }
+ String skey = key(key);
+ Object previous = context.getAttribute(skey);
+ context.setAttribute(skey, value);
+ return previous;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void putAll(Map map) {
+
+ Iterator keys = map.keySet().iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ context.setAttribute(key, map.get(key));
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object remove(Object key) {
+
+ String skey = key(key);
+ Object previous = context.getAttribute(skey);
+ context.removeAttribute(skey);
+ return previous;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int size() {
+
+ int n = 0;
+ Enumeration keys = context.getAttributeNames();
+ while (keys.hasMoreElements()) {
+ keys.nextElement();
+ n++;
+ }
+ return n;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Collection values() {
+
+ List list = new ArrayList();
+ Enumeration keys = context.getAttributeNames();
+ while (keys.hasMoreElements()) {
+ list.add(context.getAttribute((String) keys.nextElement()));
+ }
+ return list;
+
+ }
+
+
+ /**
+ * <p>Return the specified key, converted to a String.</p>
+ *
+ * @param key The key to convert
+ */
+ private String key(Object key) {
+
+ if (key == null) {
+ throw new IllegalArgumentException();
+ } else if (key instanceof String) {
+ return (String) key;
+ } else {
+ return key.toString();
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockEnumeration.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockEnumeration.java
new file mode 100644
index 0000000..19a5571
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockEnumeration.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shale.test.mock;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+
+/**
+ * <p>Mock implementation of an <code>Enumeration</code> wrapper around
+ * an <code>Iterator</code>.</p>
+ *
+ * $Id$
+ */
+
+class MockEnumeration implements Enumeration {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a wrapper instance.</p>
+ *
+ * @param iterator The <code>Iterator</code> to be wrapped
+ */
+ public MockEnumeration(Iterator iterator) {
+
+ this.iterator = iterator;
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The <code>Iterator</code> we are wrapping.</p>
+ */
+ private Iterator iterator;
+
+
+ // ----------------------------------------------------- Enumeration Methods
+
+
+ /** {@inheritDoc} */
+ public boolean hasMoreElements() {
+
+ return iterator.hasNext();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object nextElement() {
+
+ return iterator.next();
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockExternalContext.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockExternalContext.java
new file mode 100644
index 0000000..7ac79f3
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockExternalContext.java
@@ -0,0 +1,476 @@
+/*
+ * 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.shale.test.mock;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+import javax.servlet.ServletContext;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/**
+ * <p>Mock implementation of <code>ExternalContext</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockExternalContext extends ExternalContext {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Construct a wrapper instance.</p>
+ *
+ * @param context <code>ServletContext</code> for this application
+ * @param request <code>HttpServetRequest</code> for this request
+ * @param response <code>HttpServletResponse</code> for this request
+ */
+ public MockExternalContext(ServletContext context,
+ HttpServletRequest request,
+ HttpServletResponse response) {
+
+ this.context = context;
+ this.request = request;
+ this.response = response;
+ applicationMap = new MockApplicationMap(context);
+ requestMap = new MockRequestMap(request);
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private Map applicationMap = null;
+ private ServletContext context = null;
+ protected HttpServletRequest request = null;
+ private Map requestMap = null;
+ protected HttpServletResponse response = null;
+ private Map sessionMap = null;
+ private Map requestCookieMap = new HashMap();
+ private Map requestHeaderMap = new HashMap();
+ private Map requestParameterMap = new HashMap();
+
+
+ // ------------------------------------------------- setters for the mock object
+
+
+ /**
+ * <p>Add a new cookie for this request.</p>
+ *
+ * @param cookie The new cookie
+ */
+ public void addRequestCookieMap(Cookie cookie) {
+ requestParameterMap.put(cookie.getName(), cookie);
+ }
+
+
+ /**
+ * <p>Set the request cookie map for this request.</p>
+ *
+ * @param map The new request cookie map
+ */
+ public void setRequestCookieMap(Map map) {
+ requestParameterMap = map;
+ }
+
+
+ /**
+ * <p>Add the specified request parameter for this request.</p>
+ *
+ * @param key Parameter name
+ * @param value Parameter value
+ */
+ public void addRequestParameterMap(String key, String value) {
+ requestParameterMap.put(key, value);
+ }
+
+
+ /**
+ * <p>Set the request parameter map for this request.</p>
+ *
+ * @param map The new request parameter map
+ */
+ public void setRequestParameterMap(Map map) {
+ requestParameterMap = map;
+ }
+
+ /**
+ * <p>Add the specified request header for this request.</p>
+ *
+ * @param key Parameter name
+ * @param value Parameter value
+ */
+ public void addRequestHeader(String key, String value) {
+ requestHeaderMap.put(key, value);
+ }
+
+
+ /**
+ * <p>Set the request header map for this request.</p>
+ *
+ * @param map The new request header map
+ */
+ public void setRequestHeaderMap(Map map) {
+ requestHeaderMap = map;
+ }
+
+
+
+
+
+ // ------------------------------------------------- ExternalContext Methods
+
+
+ /** {@inheritDoc} */
+ public void dispatch(String requestURI)
+ throws IOException, FacesException {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String encodeActionURL(String sb) {
+
+ return sb;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String encodeNamespace(String aValue) {
+
+ return aValue;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String encodeResourceURL(String sb) {
+
+ return sb;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getApplicationMap() {
+
+ return this.applicationMap;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getAuthType() {
+
+ return request.getAuthType();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object getContext() {
+
+ return context;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getInitParameter(String name) {
+
+ return context.getInitParameter(name);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getInitParameterMap() {
+
+ Map parameterMap = new HashMap();
+ Enumeration names = context.getInitParameterNames();
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ parameterMap.put(name, context.getInitParameter(name));
+ }
+ return Collections.unmodifiableMap(parameterMap);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRemoteUser() {
+
+ return request.getRemoteUser();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object getRequest() {
+
+ return request;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRequestContextPath() {
+
+ return request.getContextPath();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getRequestCookieMap() {
+
+ return requestCookieMap;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getRequestHeaderMap() {
+
+ return requestHeaderMap;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getRequestHeaderValuesMap() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Locale getRequestLocale() {
+
+ return request.getLocale();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getRequestLocales() {
+
+ return new LocalesIterator(request.getLocales());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getRequestMap() {
+
+ return requestMap;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getRequestParameterMap() {
+
+ return requestParameterMap;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getRequestParameterNames() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getRequestParameterValuesMap() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRequestPathInfo() {
+
+ return request.getPathInfo();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRequestServletPath() {
+
+ return request.getServletPath();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public URL getResource(String path) throws MalformedURLException {
+
+ return context.getResource(path);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public InputStream getResourceAsStream(String path) {
+
+ return context.getResourceAsStream(path);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Set getResourcePaths(String path) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object getResponse() {
+
+ return response;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object getSession(boolean create) {
+
+ return request.getSession(create);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getSessionMap() {
+
+ if (sessionMap == null) {
+ HttpSession session = request.getSession(true);
+ sessionMap = new MockSessionMap(session);
+ }
+ return sessionMap;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public java.security.Principal getUserPrincipal() {
+
+ return request.getUserPrincipal();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isUserInRole(String role) {
+
+ return request.isUserInRole(role);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void log(String message) {
+
+ context.log(message);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void log(String message, Throwable throwable) {
+
+ context.log(message, throwable);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void redirect(String requestURI)
+ throws IOException {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /**
+ * <p>Iterator implementation that wraps an enumeration
+ * of Locales for the current request.</p>
+ */
+ private class LocalesIterator implements Iterator {
+
+ /**
+ * <p>Construct an iterator wrapping the specified
+ * enumeration.</p>
+ *
+ * @param locales Locales enumeration to wrap
+ */
+ public LocalesIterator(Enumeration locales) {
+ this.locales = locales;
+ }
+
+ /**
+ * <p>The enumeration to be wrapped.</p>
+ */
+ private Enumeration locales;
+
+ /** {@inheritDoc} */
+ public boolean hasNext() { return locales.hasMoreElements(); }
+
+ /** {@inheritDoc} */
+ public Object next() { return locales.nextElement(); }
+
+ /** {@inheritDoc} */
+ public void remove() { throw new UnsupportedOperationException(); }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockExternalContext12.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockExternalContext12.java
new file mode 100644
index 0000000..86e8b6e
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockExternalContext12.java
@@ -0,0 +1,120 @@
+/*
+ * 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.shale.test.mock;
+
+import java.io.UnsupportedEncodingException;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>Mock implementation of <code>ExternalContext</code> that includes the semantics
+ * added by JavaServer Faces 1.2.</p>
+ *
+ * $Id$
+ *
+ * @since 1.0.4
+ */
+
+public class MockExternalContext12 extends MockExternalContext {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ public MockExternalContext12(ServletContext context,
+ HttpServletRequest request,
+ HttpServletResponse response) {
+ super(context, request, response);
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // ------------------------------------------------- ExternalContext Methods
+
+
+ /** {@inheritDoc} */
+ public String getRequestCharacterEncoding() {
+
+ return this.request.getCharacterEncoding();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRequestContentType() {
+
+ return this.request.getContentType();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getResponseCharacterEncoding() {
+
+ return this.response.getCharacterEncoding();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getResponseContentType() {
+
+ return this.response.getContentType();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setRequest(Object request) {
+
+ this.request = (HttpServletRequest) request;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setRequestCharacterEncoding(String encoding) throws UnsupportedEncodingException {
+
+ this.request.setCharacterEncoding(encoding);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setResponse(Object response) {
+
+ this.response = (HttpServletResponse) response;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setResponseCharacterEncoding(String encoding) {
+
+ this.response.setCharacterEncoding(encoding);
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContext.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContext.java
new file mode 100644
index 0000000..adc2d53
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContext.java
@@ -0,0 +1,324 @@
+/*
+ * 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.shale.test.mock;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.faces.FactoryFinder;
+import javax.faces.application.Application;
+import javax.faces.application.FacesMessage;
+import javax.faces.application.FacesMessage.Severity;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseStream;
+import javax.faces.context.ResponseWriter;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+
+
+/**
+ * <p>Mock implementation of <code>FacesContext</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockFacesContext extends FacesContext {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ public MockFacesContext() {
+ super();
+ setCurrentInstance(this);
+ }
+
+
+ public MockFacesContext(ExternalContext externalContext) {
+ setExternalContext(externalContext);
+ setCurrentInstance(this);
+ }
+
+
+ public MockFacesContext(ExternalContext externalContext, Lifecycle lifecycle) {
+ this(externalContext);
+ this.lifecycle = lifecycle;
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ /**
+ * <p>Set the <code>Application</code> instance for this instance.</p>
+ *
+ * @param application The new Application
+ */
+ public void setApplication(Application application) {
+
+ this.application = application;
+
+ }
+
+
+ /**
+ * <p>Set the <code>ExternalContext</code> instance for this instance.</p>
+ *
+ * @param externalContext The new ExternalContext
+ */
+ public void setExternalContext(ExternalContext externalContext) {
+
+ this.externalContext = externalContext;
+
+ }
+
+
+ /**
+ * <p>Set the <code>FacesContext</code> instance for this instance.</p>
+ *
+ * @param facesContext The new FacesContext
+ */
+ public static void setCurrentInstance(FacesContext facesContext) {
+
+ FacesContext.setCurrentInstance(facesContext);
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private Application application = null;
+ private ExternalContext externalContext = null;
+ private Lifecycle lifecycle = null;
+ private Map messages = new HashMap();
+ private boolean renderResponse = false;
+ private boolean responseComplete = false;
+ private ResponseStream responseStream = null;
+ private ResponseWriter responseWriter = null;
+ private UIViewRoot viewRoot = null;
+
+
+ // ---------------------------------------------------- FacesContext Methods
+
+
+ /** {@inheritDoc} */
+ public Application getApplication() {
+
+ return this.application;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getClientIdsWithMessages() {
+
+ return messages.keySet().iterator();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ExternalContext getExternalContext() {
+
+ return this.externalContext;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Severity getMaximumSeverity() {
+
+ Severity severity = null;
+ Iterator messages = getMessages();
+ while (messages.hasNext()) {
+ FacesMessage message = (FacesMessage) messages.next();
+ if (severity == null) {
+ severity = message.getSeverity();
+ } else if (message.getSeverity().getOrdinal() > severity.getOrdinal()) {
+ severity = message.getSeverity();
+ }
+ }
+ return severity;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getMessages() {
+
+ ArrayList results = new ArrayList();
+ Iterator clientIds = messages.keySet().iterator();
+ while (clientIds.hasNext()) {
+ String clientId = (String) clientIds.next();
+ results.addAll((List) messages.get(clientId));
+ }
+ return results.iterator();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Iterator getMessages(String clientId) {
+
+ List list = (List) messages.get(clientId);
+ if (list == null) {
+ list = new ArrayList();
+ }
+ return list.iterator();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public RenderKit getRenderKit() {
+
+ UIViewRoot vr = getViewRoot();
+ if (vr == null) {
+ return null;
+ }
+ String renderKitId = vr.getRenderKitId();
+ if (renderKitId == null) {
+ return null;
+ }
+ RenderKitFactory rkFactory = (RenderKitFactory)
+ FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+ return rkFactory.getRenderKit(this, renderKitId);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean getRenderResponse() {
+
+ return this.renderResponse;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean getResponseComplete() {
+
+ return this.responseComplete;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ResponseStream getResponseStream() {
+
+ return this.responseStream;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setResponseStream(ResponseStream responseStream) {
+
+ this.responseStream = responseStream;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ResponseWriter getResponseWriter() {
+
+ return this.responseWriter;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setResponseWriter(ResponseWriter responseWriter) {
+
+ this.responseWriter = responseWriter;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public UIViewRoot getViewRoot() {
+
+ return this.viewRoot;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setViewRoot(UIViewRoot viewRoot) {
+
+ this.viewRoot = viewRoot;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addMessage(String clientId, FacesMessage message) {
+
+ if (message == null) {
+ throw new NullPointerException();
+ }
+ List list = (List) messages.get(clientId);
+ if (list == null) {
+ list = new ArrayList();
+ messages.put(clientId, list);
+ }
+ list.add(message);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void release() {
+
+ application = null;
+ externalContext = null;
+ messages.clear();
+ renderResponse = false;
+ responseComplete = false;
+ responseStream = null;
+ responseWriter = null;
+ viewRoot = null;
+ setCurrentInstance(null);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void renderResponse() {
+
+ this.renderResponse = true;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void responseComplete() {
+
+ this.responseComplete = true;
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContext12.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContext12.java
new file mode 100644
index 0000000..e5ed652
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContext12.java
@@ -0,0 +1,114 @@
+/*
+ * 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.shale.test.mock;
+
+import javax.el.ELContext;
+import javax.el.ELContextEvent;
+import javax.el.ELContextListener;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.lifecycle.Lifecycle;
+import org.apache.shale.test.el.MockELContext;
+
+/**
+ * <p>Mock implementation of <code>FacesContext</code> that includes the semantics
+ * added by JavaServer Faces 1.2.</p>
+ *
+ * $Id$
+ *
+ * @since 1.0.4
+ */
+
+public class MockFacesContext12 extends MockFacesContext {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ public MockFacesContext12() {
+ super();
+ setCurrentInstance(this);
+ }
+
+
+ public MockFacesContext12(ExternalContext externalContext) {
+ super(externalContext);
+ }
+
+
+ public MockFacesContext12(ExternalContext externalContext, Lifecycle lifecycle) {
+ super(externalContext, lifecycle);
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ /**
+ * <p>Set the <code>ELContext</code> instance for this instance.</p>
+ *
+ * @param elContext The new ELContext
+ */
+ public void setELContext(ELContext elContext) {
+
+ this.elContext = elContext;
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private ELContext elContext = null;
+
+
+ // ---------------------------------------------------- FacesContext Methods
+
+
+ /** {@inheritDoc} */
+ public ELContext getELContext() {
+
+ if (this.elContext == null) {
+
+ // Initialize a new ELContext
+ this.elContext = new MockELContext();
+ this.elContext.putContext(FacesContext.class, this);
+
+ // Notify interested listeners that this ELContext was created
+ ELContextListener[] listeners = getApplication().getELContextListeners();
+ if ((listeners != null) && (listeners.length > 0)) {
+ ELContextEvent event = new ELContextEvent(this.elContext);
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].contextCreated(event);
+ }
+ }
+
+ }
+ return this.elContext;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void release() {
+ super.release();
+ this.elContext = null;
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContextFactory.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContextFactory.java
new file mode 100644
index 0000000..9b6aee9
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockFacesContextFactory.java
@@ -0,0 +1,175 @@
+/*
+ * 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.shale.test.mock;
+
+import java.lang.reflect.Constructor;
+import javax.faces.FacesException;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.FacesContextFactory;
+import javax.faces.lifecycle.Lifecycle;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>Mock implementation of <code>FacesContextFactory</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockFacesContextFactory extends FacesContextFactory {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Look up the constructor we will use for creating <code>MockFacesContext</code>
+ * instances.</p>
+ */
+ public MockFacesContextFactory() {
+
+ Class clazz = null;
+
+ // Try to load the 1.2 version of our mock FacesContext class
+ try {
+ clazz = this.getClass().getClassLoader().loadClass("org.apache.shale.test.mock.MockFacesContext12");
+ constructor = clazz.getConstructor(facesContextSignature);
+ jsf12 = true;
+ } catch (NoClassDefFoundError e) {
+ // We are not running on JSF 1.2, so go to our fallback
+ clazz = null;
+ constructor = null;
+ } catch (ClassNotFoundException e) {
+ // Same as above
+ clazz = null;
+ constructor = null;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ // Fall back to the 1.1 version if we could not load the 1.2 version
+ try {
+ if (clazz == null) {
+ clazz = this.getClass().getClassLoader().loadClass("org.apache.shale.test.mock.MockFacesContext");
+ constructor = clazz.getConstructor(facesContextSignature);
+ jsf12 = false;
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>The constructor for creating a <code>FacesContext</code> instance,
+ * taking an <code>ExternalContext</code> and <code>Lifecycle</code>.</p>
+ */
+ private Constructor constructor = null;
+
+
+ /**
+ * <p>The parameter signature of the ExternalContext constructor we wish to call.</p>
+ */
+ private static Class[] externalContextSignature = new Class[] {
+ ServletContext.class, HttpServletRequest.class, HttpServletResponse.class
+ };
+
+
+ /**
+ * <p>The parameter signature of the FacesContext constructor we wish to call.</p>
+ */
+ private static Class[] facesContextSignature = new Class[] {
+ ExternalContext.class, Lifecycle.class
+ };
+
+
+ /**
+ * <p>Flag indicating that we are running in a JSF 1.2 environment.</p>
+ */
+ private boolean jsf12 = false;
+
+
+ // --------------------------------------------- FacesContextFactory Methods
+
+
+ /** {@inheritDoc} */
+ public FacesContext getFacesContext(Object context, Object request,
+ Object response,
+ Lifecycle lifecycle) throws FacesException {
+
+ // Select the appropriate MockExternalContext implementation class
+ Class clazz = MockExternalContext.class;
+ if (jsf12) {
+ try {
+ clazz = this.getClass().getClassLoader().loadClass
+ ("org.apache.shale.test.mock.MockExternalContext12");
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+ }
+
+ // Select the constructor we wish to call
+ Constructor mecConstructor = null;
+ try {
+ mecConstructor = clazz.getConstructor(externalContextSignature);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ // Construct an appropriate MockExternalContext instance
+ MockExternalContext externalContext = null;
+ try {
+ externalContext = (MockExternalContext) mecConstructor.newInstance
+ (new Object[] { context, request, response });
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ // Construct an appropriate MockFacesContext instance and return it
+ try {
+ return (MockFacesContext)
+ constructor.newInstance(new Object[] { externalContext, lifecycle });
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new FacesException(e);
+ }
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpServletRequest.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpServletRequest.java
new file mode 100644
index 0000000..e8d2bb8
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpServletRequest.java
@@ -0,0 +1,894 @@
+/*
+ * 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.shale.test.mock;
+
+import java.io.BufferedReader;
+import java.security.Principal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+
+/**
+ * <p>Mock implementation of <code>HttpServletContext</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockHttpServletRequest implements HttpServletRequest {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ public MockHttpServletRequest() {
+
+ super();
+
+ }
+
+
+ public MockHttpServletRequest(HttpSession session) {
+
+ super();
+ setHttpSession(session);
+
+ }
+
+
+ public MockHttpServletRequest(String contextPath, String servletPath,
+ String pathInfo, String queryString) {
+
+ super();
+ setPathElements(contextPath, servletPath, pathInfo, queryString);
+
+ }
+
+
+
+ public MockHttpServletRequest(String contextPath, String servletPath,
+ String pathInfo, String queryString,
+ HttpSession session) {
+
+ super();
+ setPathElements(contextPath, servletPath, pathInfo, queryString);
+ setHttpSession(session);
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ /**
+ * <p>Add a new listener instance that should be notified about
+ * attribute changes.</p>
+ *
+ * @param listener The new listener to register
+ */
+ public void addAttributeListener(ServletRequestAttributeListener listener) {
+ attributeListeners.add(listener);
+ }
+
+
+ /**
+ * <p>Add a date-valued header for this request.</p>
+ *
+ * @param name Header name
+ * @param value Header value
+ */
+ public void addDateHeader(String name, long value) {
+
+ headers.add(name + ": " + formatDate(value));
+
+ }
+
+
+ /**
+ * <p>Add a String-valued header for this request.</p>
+ *
+ * @param name Header name
+ * @param value Header value
+ */
+ public void addHeader(String name, String value) {
+
+ headers.add(name + ": " + value);
+
+ }
+
+
+ /**
+ * <p>Add an integer-valued header for this request.</p>
+ *
+ * @param name Header name
+ * @param value Header value
+ */
+ public void addIntHeader(String name, int value) {
+
+ headers.add(name + ": " + value);
+
+ }
+
+
+ /**
+ * <p>Add a request parameter for this request.</p>
+ *
+ * @param name Parameter name
+ * @param value Parameter value
+ */
+ public void addParameter(String name, String value) {
+
+ String[] values = (String[]) parameters.get(name);
+ if (values == null) {
+ String[] results = new String[] { value };
+ parameters.put(name, results);
+ return;
+ }
+ String[] results = new String[values.length + 1];
+ System.arraycopy(values, 0, results, 0, values.length);
+ results[values.length] = value;
+ parameters.put(name, results);
+
+ }
+
+
+ /**
+ * <p>Return the <code>ServletContext</code> associated with
+ * this request.</p>
+ */
+ public ServletContext getServletContext() {
+
+ return this.servletContext;
+
+ }
+
+
+ /**
+ * <p>Set the <code>HttpSession</code> associated with this request.</p>
+ *
+ * @param session The new session
+ */
+ public void setHttpSession(HttpSession session) {
+
+ this.session = session;
+
+ }
+
+
+ /**
+ * <p>Set the <code>Locale</code> associated with this request.</p>
+ *
+ * @param locale The new locale
+ */
+ public void setLocale(Locale locale) {
+
+ this.locale = locale;
+
+ }
+
+
+ /**
+ * <p>Set the parsed path elements associated with this request.</p>
+ *
+ * @param contextPath The context path
+ * @param servletPath The servlet path
+ * @param pathInfo The extra path information
+ * @param queryString The query string
+ */
+ public void setPathElements(String contextPath, String servletPath,
+ String pathInfo, String queryString) {
+
+ this.contextPath = contextPath;
+ this.servletPath = servletPath;
+ this.pathInfo = pathInfo;
+ this.queryString = queryString;
+
+ }
+
+
+ /**
+ * <p>Set the <code>ServletContext</code> associated with this request.</p>
+ *
+ * @param servletContext The new servlet context
+ */
+ public void setServletContext(ServletContext servletContext) {
+
+ this.servletContext = servletContext;
+
+ }
+
+
+ /**
+ * <p>Set the <code>Principal</code> associated with this request.</p>
+ *
+ * @param principal The new Principal
+ */
+ public void setUserPrincipal(Principal principal) {
+
+ this.principal = principal;
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private List attributeListeners = new ArrayList();
+ private HashMap attributes = new HashMap();
+ private String contextPath = null;
+ private List headers = new ArrayList();
+ private Locale locale = null;
+ private HashMap parameters = new HashMap();
+ private String pathInfo = null;
+ private Principal principal = null;
+ private String queryString = null;
+ private ServletContext servletContext = null;
+ private String servletPath = null;
+ private HttpSession session = null;
+ private String characterEncoding = null;
+
+
+ // ---------------------------------------------- HttpServletRequest Methods
+
+
+ /** {@inheritDoc} */
+ public String getAuthType() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getContextPath() {
+
+ return contextPath;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Cookie[] getCookies() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public long getDateHeader(String name) {
+
+ String match = name + ":";
+ Iterator headers = this.headers.iterator();
+ while (headers.hasNext()) {
+ String header = (String) headers.next();
+ if (header.startsWith(match)) {
+ return parseDate(header.substring(match.length() + 1).trim());
+ }
+ }
+ return (long) -1;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getHeader(String name) {
+
+ String match = name + ":";
+ Iterator headers = this.headers.iterator();
+ while (headers.hasNext()) {
+ String header = (String) headers.next();
+ if (header.startsWith(match)) {
+ return header.substring(match.length() + 1).trim();
+ }
+ }
+ return null;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getHeaderNames() {
+
+ Vector values = new Vector();
+ Iterator headers = this.headers.iterator();
+ while (headers.hasNext()) {
+ String header = (String) headers.next();
+ int colon = header.indexOf(':');
+ if (colon >= 0) {
+ String name = header.substring(0, colon).trim();
+ if (!values.contains(name)) {
+ values.add(name);
+ }
+ }
+ }
+ return values.elements();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getHeaders(String name) {
+
+ String match = name + ":";
+ Vector values = new Vector();
+ Iterator headers = this.headers.iterator();
+ while (headers.hasNext()) {
+ String header = (String) headers.next();
+ if (header.startsWith(match)) {
+ values.add(header.substring(match.length() + 1).trim());
+ }
+ }
+ return values.elements();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getIntHeader(String name) {
+
+ String match = name + ":";
+ Iterator headers = this.headers.iterator();
+ while (headers.hasNext()) {
+ String header = (String) headers.next();
+ if (header.startsWith(match)) {
+ return Integer.parseInt(header.substring(match.length() + 1).trim());
+ }
+ }
+ return -1;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getMethod() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getPathInfo() {
+
+ return pathInfo;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getPathTranslated() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getQueryString() {
+
+ return queryString;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRemoteUser() {
+
+ if (principal != null) {
+ return principal.getName();
+ } else {
+ return null;
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRequestedSessionId() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRequestURI() {
+
+ StringBuffer sb = new StringBuffer();
+ if (contextPath != null) {
+ sb.append(contextPath);
+ }
+ if (servletPath != null) {
+ sb.append(servletPath);
+ }
+ if (pathInfo != null) {
+ sb.append(pathInfo);
+ }
+ if (sb.length() > 0) {
+ return sb.toString();
+ }
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public StringBuffer getRequestURL() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getServletPath() {
+
+ return (servletPath);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public HttpSession getSession() {
+
+ return getSession(true);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public HttpSession getSession(boolean create) {
+
+ if (create && (session == null)) {
+ throw new UnsupportedOperationException();
+ }
+ return session;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Principal getUserPrincipal() {
+
+ return principal;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isRequestedSessionIdFromCookie() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isRequestedSessionIdFromUrl() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isRequestedSessionIdFromURL() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isRequestedSessionIdValid() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isUserInRole(String role) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ // ------------------------------------------------- ServletRequest Methods
+
+
+ /** {@inheritDoc} */
+ public Object getAttribute(String name) {
+
+ return attributes.get(name);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getAttributeNames() {
+
+ return new MockEnumeration(attributes.keySet().iterator());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getCharacterEncoding() {
+
+ return characterEncoding;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getContentLength() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getContentType() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ServletInputStream getInputStream() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Locale getLocale() {
+
+ return locale;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getLocales() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getLocalAddr() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getLocalName() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getLocalPort() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getParameter(String name) {
+
+ String[] values = (String[]) parameters.get(name);
+ if (values != null) {
+ return values[0];
+ } else {
+ return null;
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getParameterMap() {
+
+ return parameters;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getParameterNames() {
+
+ return new MockEnumeration(parameters.keySet().iterator());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String[] getParameterValues(String name) {
+
+ return (String[]) parameters.get(name);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getProtocol() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public BufferedReader getReader() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRealPath(String path) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRemoteAddr() {
+
+ // i figure testing never assumes a specific remote - so anything works
+ return "1.2.3.4";
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRemoteHost() {
+
+ // i figure testing never assumes a specific remote - so anything works
+ return "ShaleServer";
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getRemotePort() {
+
+ // i figure testing never assumes a specific remote - so anything works
+ return 46123;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public RequestDispatcher getRequestDispatcher(String path) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getScheme() {
+
+ return ("http");
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getServerName() {
+
+ return ("localhost");
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getServerPort() {
+
+ return (8080);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isSecure() {
+
+ return false;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void removeAttribute(String name) {
+
+ if (attributes.containsKey(name)) {
+ Object value = attributes.remove(name);
+ fireAttributeRemoved(name, value);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setAttribute(String name, Object value) {
+
+ if (name == null) {
+ throw new IllegalArgumentException("Attribute name cannot be null");
+ }
+ if (value == null) {
+ removeAttribute(name);
+ return;
+ }
+ if (attributes.containsKey(name)) {
+ Object oldValue = attributes.get(name);
+ attributes.put(name, value);
+ fireAttributeReplaced(name, oldValue);
+ } else {
+ attributes.put(name, value);
+ fireAttributeAdded(name, value);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setCharacterEncoding(String characterEncoding) {
+
+ this.characterEncoding = characterEncoding;
+
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>Fire an attribute added event to interested listeners.</p>
+ *
+ * @param key Attribute key whose value was added
+ * @param value The new attribute value
+ */
+ private void fireAttributeAdded(String key, Object value) {
+ if (attributeListeners.size() < 1) {
+ return;
+ }
+ ServletRequestAttributeEvent event =
+ new ServletRequestAttributeEvent(getServletContext(), this, key, value);
+ Iterator listeners = attributeListeners.iterator();
+ while (listeners.hasNext()) {
+ ServletRequestAttributeListener listener =
+ (ServletRequestAttributeListener) listeners.next();
+ listener.attributeAdded(event);
+ }
+ }
+
+
+ /**
+ * <p>Fire an attribute removed event to interested listeners.</p>
+ *
+ * @param key Attribute key whose value was removed
+ * @param value Attribute value that was removed
+ */
+ private void fireAttributeRemoved(String key, Object value) {
+ if (attributeListeners.size() < 1) {
+ return;
+ }
+ ServletRequestAttributeEvent event =
+ new ServletRequestAttributeEvent(getServletContext(), this, key, value);
+ Iterator listeners = attributeListeners.iterator();
+ while (listeners.hasNext()) {
+ ServletRequestAttributeListener listener =
+ (ServletRequestAttributeListener) listeners.next();
+ listener.attributeRemoved(event);
+ }
+ }
+
+
+ /**
+ * <p>Fire an attribute replaced event to interested listeners.</p>
+ *
+ * @param key Attribute key whose value was replaced
+ * @param value The original value
+ */
+ private void fireAttributeReplaced(String key, Object value) {
+ if (attributeListeners.size() < 1) {
+ return;
+ }
+ ServletRequestAttributeEvent event =
+ new ServletRequestAttributeEvent(getServletContext(), this, key, value);
+ Iterator listeners = attributeListeners.iterator();
+ while (listeners.hasNext()) {
+ ServletRequestAttributeListener listener =
+ (ServletRequestAttributeListener) listeners.next();
+ listener.attributeReplaced(event);
+ }
+ }
+
+
+ /**
+ * <p>The date formatting helper we will use in <code>httpTimestamp()</code>.
+ * Note that usage of this helper must be synchronized.</p>
+ */
+ private static SimpleDateFormat format =
+ new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
+ static {
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+
+
+ /**
+ * <p>Return a properly formatted String version of the specified
+ * date/time, formatted as required by the HTTP specification.</p>
+ *
+ * @param date Date/time, expressed as milliseconds since the epoch
+ */
+ private String formatDate(long date) {
+ return format.format(new Date(date));
+ }
+
+
+ /**
+ * <p>Return a date/time value, parsed from the specified String.</p>
+ *
+ * @param date Date/time, expressed as a String
+ */
+ private long parseDate(String date) {
+ try {
+ return format.parse(date).getTime();
+ } catch (ParseException e) {
+ throw new IllegalArgumentException(date);
+ }
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpServletResponse.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpServletResponse.java
new file mode 100644
index 0000000..fdbcb5b
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpServletResponse.java
@@ -0,0 +1,454 @@
+/*
+ * 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.shale.test.mock;
+
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>Mock implementation of <code>HttpServletResponse</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockHttpServletResponse implements HttpServletResponse {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Return a default instance.</p>
+ */
+ public MockHttpServletResponse() { }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ /**
+ * <p>Retrieve the first value that was set for the specified header,
+ * if any. Otherwise, return <code>null</code>.</p>
+ *
+ * @param name Header name to look up
+ */
+ public String getHeader(String name) {
+ String match = name + ":";
+ Iterator headers = this.headers.iterator();
+ while (headers.hasNext()) {
+ String header = (String) headers.next();
+ if (header.startsWith(match)) {
+ return header.substring(match.length() + 1).trim();
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * <p>Return the text message for the HTTP status that was set.</p>
+ */
+ public String getMessage() {
+ return this.message;
+ }
+
+
+ /**
+ * <p>Return the HTTP status code that was set.</p>
+ */
+ public int getStatus() {
+ return this.status;
+ }
+
+
+ /**
+ * <p>Set the <code>ServletOutputStream</code> to be returned by a call to
+ * <code>getOutputStream()</code>.</p>
+ *
+ * @param stream The <code>ServletOutputStream</code> instance to use
+ *
+ * @deprecated Let the <code>getOutputStream()</code> method create and
+ * return an instance of <code>MockServletOutputStream</code> for you
+ */
+ public void setOutputStream(ServletOutputStream stream) {
+ this.stream = stream;
+ }
+
+
+ /**
+ * <p>Set the <code>PrintWriter</code> to be returned by a call to
+ * <code>getWriter()</code>.</p>
+ *
+ * @param writer The <code>PrintWriter</code> instance to use
+ *
+ * @deprecated Let the <code>getWriter()</code> method create and return
+ * an instance of <code>MockPrintWriter</code> for you
+ */
+ public void setWriter(PrintWriter writer) {
+ this.writer = writer;
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private String encoding = "ISO-8859-1";
+ private String contentType = "text/html";
+ private List headers = new ArrayList();
+ private String message = null;
+ private int status = HttpServletResponse.SC_OK;
+ private ServletOutputStream stream = null;
+ private PrintWriter writer = null;
+
+
+ // -------------------------------------------- HttpServletResponse Methods
+
+
+ /** {@inheritDoc} */
+ public void addCookie(Cookie cookie) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addDateHeader(String name, long value) {
+
+ headers.add(name + ": " + formatDate(value));
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addHeader(String name, String value) {
+
+ headers.add(name + ": " + value);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void addIntHeader(String name, int value) {
+
+ headers.add(name + ": " + value);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean containsHeader(String name) {
+
+ return getHeader(name) != null;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String encodeRedirectUrl(String url) {
+
+ return encodeRedirectURL(url);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String encodeRedirectURL(String url) {
+
+ return url;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String encodeUrl(String url) {
+
+ return encodeURL(url);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String encodeURL(String url) {
+
+ return url;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void sendError(int status) {
+
+ this.status = status;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void sendError(int status, String message) {
+
+ this.status = status;
+ this.message = message;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void sendRedirect(String location) {
+
+ this.status = HttpServletResponse.SC_MOVED_TEMPORARILY;
+ this.message = location;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setDateHeader(String name, long value) {
+
+ removeHeader(name);
+ addDateHeader(name, value);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setHeader(String name, String value) {
+
+ removeHeader(name);
+ addHeader(name, value);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setIntHeader(String name, int value) {
+
+ removeHeader(name);
+ addIntHeader(name, value);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setStatus(int status) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setStatus(int status, String message) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ // ------------------------------------------------ ServletResponse Methods
+
+
+ /** {@inheritDoc} */
+ public void flushBuffer() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getBufferSize() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getCharacterEncoding() {
+
+ return this.encoding;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getContentType() {
+
+ return this.contentType;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Locale getLocale() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ServletOutputStream getOutputStream() throws IOException {
+
+ if (stream == null) {
+ if (writer != null) {
+ throw new IllegalStateException("Cannot call getOutputStream() after getWriter() has been called");
+ }
+ stream = new MockServletOutputStream(new ByteArrayOutputStream());
+ }
+ return stream;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public PrintWriter getWriter() throws IOException {
+
+ if (writer == null) {
+ if (stream != null) {
+ throw new IllegalStateException("Cannot call getWriter() after getOutputStream() was called");
+ }
+ writer = new MockPrintWriter(new CharArrayWriter());
+ }
+ return writer;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isCommitted() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void reset() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void resetBuffer() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setBufferSize(int size) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setCharacterEncoding(String charset) {
+
+ this.encoding = charset;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setContentLength(int length) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setContentType(String type) {
+
+ contentType = type;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setLocale(Locale locale) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>The date formatting helper we will use in <code>httpTimestamp()</code>.
+ * Note that usage of this helper must be synchronized.</p>
+ */
+ private static SimpleDateFormat format =
+ new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
+ static {
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+
+
+ /**
+ * <p>Return a properly formatted String version of the specified
+ * date/time, formatted as required by the HTTP specification.</p>
+ *
+ * @param date Date/time, expressed as milliseconds since the epoch
+ */
+ private String formatDate(long date) {
+ return format.format(new Date(date));
+ }
+
+
+ /**
+ * <p>Remove any header that has been set with the specific name.</p>
+ *
+ * @param name Header name to look up
+ */
+ private void removeHeader(String name) {
+ String match = name + ":";
+ Iterator headers = this.headers.iterator();
+ while (headers.hasNext()) {
+ String header = (String) headers.next();
+ if (header.startsWith(match)) {
+ headers.remove();
+ return;
+ }
+ }
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpSession.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpSession.java
new file mode 100644
index 0000000..e32a27c
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockHttpSession.java
@@ -0,0 +1,338 @@
+/*
+ * 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.shale.test.mock;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionContext;
+
+/**
+ * <p>Mock implementation of <code>HttpSession</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockHttpSession implements HttpSession {
+
+
+ // ------------------------------------------------------------ Constructors
+
+
+ /**
+ * <p>Configure a default instance.</p>
+ */
+ public MockHttpSession() {
+
+ super();
+
+ }
+
+
+ /**
+ * <p>Configure a session instance associated with the specified
+ * servlet context.</p>
+ *
+ * @param servletContext The associated servlet context
+ */
+ public MockHttpSession(ServletContext servletContext) {
+
+ super();
+ setServletContext(servletContext);
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ /**
+ * <p>Add a new listener instance that should be notified about
+ * attribute changes.</p>
+ *
+ * @param listener The new listener to be added
+ */
+ public void addAttributeListener(HttpSessionAttributeListener listener) {
+ attributeListeners.add(listener);
+ }
+
+
+ /**
+ * <p>Set the ServletContext associated with this session.</p>
+ *
+ * @param servletContext The associated servlet context
+ */
+ public void setServletContext(ServletContext servletContext) {
+
+ this.servletContext = servletContext;
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private List attributeListeners = new ArrayList();
+ private HashMap attributes = new HashMap();
+ private String id = "123";
+ private ServletContext servletContext = null;
+
+
+ // ---------------------------------------------------------- Public Methods
+
+
+ /**
+ * <p>Set the session identifier of this session.</p>
+ *
+ * @param id The new session identifier
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+
+ // ----------------------------------------------------- HttpSession Methods
+
+
+ /** {@inheritDoc} */
+ public Object getAttribute(String name) {
+
+ return attributes.get(name);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getAttributeNames() {
+
+ return new MockEnumeration(attributes.keySet().iterator());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public long getCreationTime() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getId() {
+
+ return this.id;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public long getLastAccessedTime() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getMaxInactiveInterval() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public ServletContext getServletContext() {
+
+ return this.servletContext;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public HttpSessionContext getSessionContext() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object getValue(String name) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String[] getValueNames() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void invalidate() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isNew() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void putValue(String name, Object value) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void removeAttribute(String name) {
+
+ if (attributes.containsKey(name)) {
+ Object value = attributes.remove(name);
+ fireAttributeRemoved(name, value);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void removeValue(String name) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setAttribute(String name, Object value) {
+
+ if (name == null) {
+ throw new IllegalArgumentException("Attribute name cannot be null");
+ }
+ if (value == null) {
+ removeAttribute(name);
+ return;
+ }
+ if (attributes.containsKey(name)) {
+ Object oldValue = attributes.get(name);
+ attributes.put(name, value);
+ fireAttributeReplaced(name, oldValue);
+ } else {
+ attributes.put(name, value);
+ fireAttributeAdded(name, value);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setMaxInactiveInterval(int interval) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ // --------------------------------------------------------- Support Methods
+
+
+ /**
+ * <p>Fire an attribute added event to interested listeners.</p>
+ *
+ * @param key Attribute whose value was added
+ * @param value The new value
+ */
+ private void fireAttributeAdded(String key, Object value) {
+ if (attributeListeners.size() < 1) {
+ return;
+ }
+ HttpSessionBindingEvent event =
+ new HttpSessionBindingEvent(this, key, value);
+ Iterator listeners = attributeListeners.iterator();
+ while (listeners.hasNext()) {
+ HttpSessionAttributeListener listener =
+ (HttpSessionAttributeListener) listeners.next();
+ listener.attributeAdded(event);
+ }
+ }
+
+
+ /**
+ * <p>Fire an attribute removed event to interested listeners.</p>
+ *
+ * @param key Attribute whose value was removed
+ * @param value The removed value
+ */
+ private void fireAttributeRemoved(String key, Object value) {
+ if (attributeListeners.size() < 1) {
+ return;
+ }
+ HttpSessionBindingEvent event =
+ new HttpSessionBindingEvent(this, key, value);
+ Iterator listeners = attributeListeners.iterator();
+ while (listeners.hasNext()) {
+ HttpSessionAttributeListener listener =
+ (HttpSessionAttributeListener) listeners.next();
+ listener.attributeRemoved(event);
+ }
+ }
+
+
+ /**
+ * <p>Fire an attribute replaced event to interested listeners.</p>
+ *
+ * @param key Attribute whose value was replaced
+ * @param value The original value
+ */
+ private void fireAttributeReplaced(String key, Object value) {
+ if (attributeListeners.size() < 1) {
+ return;
+ }
+ HttpSessionBindingEvent event =
+ new HttpSessionBindingEvent(this, key, value);
+ Iterator listeners = attributeListeners.iterator();
+ while (listeners.hasNext()) {
+ HttpSessionAttributeListener listener =
+ (HttpSessionAttributeListener) listeners.next();
+ listener.attributeReplaced(event);
+ }
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockMethodBinding.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockMethodBinding.java
new file mode 100644
index 0000000..2a7a39c
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockMethodBinding.java
@@ -0,0 +1,249 @@
+/*
+ * 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.shale.test.mock;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import javax.faces.application.Application;
+import javax.faces.component.StateHolder;
+import javax.faces.component.UIComponentBase;
+import javax.faces.context.FacesContext;
+import javax.faces.el.EvaluationException;
+import javax.faces.el.MethodBinding;
+import javax.faces.el.MethodNotFoundException;
+import javax.faces.el.ReferenceSyntaxException;
+import javax.faces.el.ValueBinding;
+
+/**
+ * <p>Mock implementation of <code>MethodBinding</code>.</p>
+ *
+ * <p>This implementation is subject to the following restrictions:</p>
+ * <ul>
+ * <li>The portion of the method reference expression before the final
+ * "." must conform to the limitations of {@link MockValueBinding}.</li>
+ * <li>The name of the method to be executed cannot be delimited by "[]".</li>
+ * </ul>
+ */
+
+public class MockMethodBinding extends MethodBinding implements StateHolder {
+
+
+ // ------------------------------------------------------------ Constructors
+
+ /**
+ * <p>Construct a default instance.</p>
+ */
+ public MockMethodBinding() {
+ }
+
+
+ /**
+ * <p>Construct a configured instance.</p>
+ *
+ * @param application Application instance for this application
+ * @param ref Method binding expression to be parsed
+ * @param args Signature of this method
+ */
+ public MockMethodBinding(Application application, String ref,
+ Class[] args) {
+
+ this.application = application;
+ this.args = args;
+ if (ref.startsWith("#{") && ref.endsWith("}")) {
+ ref = ref.substring(2, ref.length() - 1);
+ }
+ this.ref = ref;
+ int period = ref.lastIndexOf(".");
+ if (period < 0) {
+ throw new ReferenceSyntaxException(ref);
+ }
+ vb = application.createValueBinding(ref.substring(0, period));
+ name = ref.substring(period + 1);
+ if (name.length() < 1) {
+ throw new ReferenceSyntaxException(ref);
+ }
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ private Application application;
+ private Class args[];
+ private String name;
+ private String ref;
+ private ValueBinding vb;
+
+
+ // --------------------------------------------------- MethodBinding Methods
+
+
+ /** {@inheritDoc} */
+ public Object invoke(FacesContext context, Object[] params)
+ throws EvaluationException, MethodNotFoundException {
+
+ if (context == null) {
+ throw new NullPointerException();
+ }
+ Object base = vb.getValue(context);
+ if (base == null) {
+ throw new EvaluationException("Cannot find object via expression \""
+ + vb.getExpressionString() + "\"");
+ }
+ Method method = method(base);
+ try {
+ return (method.invoke(base, params));
+ } catch (IllegalAccessException e) {
+ throw new EvaluationException(e);
+ } catch (InvocationTargetException e) {
+ throw new EvaluationException(e.getTargetException());
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Class getType(FacesContext context) {
+
+ Object base = vb.getValue(context);
+ Method method = method(base);
+ Class returnType = method.getReturnType();
+ if ("void".equals(returnType.getName())) {
+ return (null);
+ } else {
+ return (returnType);
+ }
+
+ }
+
+ /** {@inheritDoc} */
+ public String getExpressionString() {
+ return "#{" + ref + "}";
+ }
+
+ // ----------------------------------------------------- StateHolder Methods
+
+
+ /** {@inheritDoc} */
+ public Object saveState(FacesContext context) {
+ Object values[] = new Object[4];
+ values[0] = name;
+ values[1] = ref;
+ values[2] = UIComponentBase.saveAttachedState(context, vb);
+ values[3] = args;
+ return (values);
+ }
+
+
+ /** {@inheritDoc} */
+ public void restoreState(FacesContext context, Object state) {
+ Object values[] = (Object[]) state;
+ name = (String) values[0];
+ ref = (String) values[1];
+ vb = (ValueBinding) UIComponentBase.restoreAttachedState(context,
+ values[2]);
+ args = (Class []) values[3];
+ }
+
+
+ /**
+ * <p>Flag indicating this is a transient instance.</p>
+ */
+ private boolean transientFlag = false;
+
+
+ /** {@inheritDoc} */
+ public boolean isTransient() {
+ return (this.transientFlag);
+ }
+
+
+ /** {@inheritDoc} */
+ public void setTransient(boolean transientFlag) {
+ this.transientFlag = transientFlag;
+ }
+
+ /** {@inheritDoc} */
+ public int hashCode() {
+ if (ref == null) {
+ return 0;
+ } else {
+ return ref.hashCode();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean equals(Object otherObj) {
+ MockMethodBinding other = null;
+
+ if (!(otherObj instanceof MockMethodBinding)) {
+ return false;
+ }
+ other = (MockMethodBinding) otherObj;
+ // test object reference equality
+ if (this.ref != other.ref) {
+ // test object equality
+ if (null != this.ref && null != other.ref) {
+ if (!this.ref.equals(other.ref)) {
+ return false;
+ }
+ }
+ return false;
+ }
+ // no need to test name, since it flows from ref.
+ // test our args array
+ if (this.args != other.args) {
+ if (this.args.length != other.args.length) {
+ return false;
+ }
+ for (int i = 0, len = this.args.length; i < len; i++) {
+ if (this.args[i] != other.args[i]) {
+ if (!this.ref.equals(other.ref)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>Return the <code>Method</code> to be called.</p>
+ *
+ * @param base Base object from which to extract the method reference
+ */
+ Method method(Object base) {
+
+ Class clazz = base.getClass();
+ try {
+ return (clazz.getMethod(name, args));
+ } catch (NoSuchMethodException e) {
+ throw new MethodNotFoundException(ref + ": " + e.getMessage());
+ }
+
+ }
+
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockNavigationHandler.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockNavigationHandler.java
new file mode 100644
index 0000000..c93dbd0
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockNavigationHandler.java
@@ -0,0 +1,110 @@
+/*
+ * 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.shale.test.mock;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.faces.application.NavigationHandler;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+/**
+ * <p>Mock implementation of <code>NavigationHandler</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockNavigationHandler extends NavigationHandler {
+
+
+ // ------------------------------------------------------------ Constructors
+
+ /**
+ * <p>Construct a default instance.</p>
+ */
+ public MockNavigationHandler() {
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+
+ /**
+ * <p>Add a outcome-viewId pair to the destinations map.</p>
+ *
+ * @param outcome Logical outcome string
+ * @param viewId Destination view identifier
+ */
+ public void addDestination(String outcome, String viewId) {
+
+ destinations.put(outcome, viewId);
+
+ }
+
+
+ // ------------------------------------------------------ Instance Variables
+
+
+ /**
+ * <p>Set of destination view ids, keyed by logical outcome String
+ * that will cause navigation to that view id.</p>
+ */
+ private Map destinations = new HashMap();
+
+
+ // ----------------------------------------------- NavigationHandler Methods
+
+
+ /**
+ * <p>Process the specified navigation request.</p>
+ *
+ * @param context <code>FacesContext</code> for the current request
+ * @param action Action method being executed
+ * @param outcome Logical outcome from this action method
+ */
+ public void handleNavigation(FacesContext context,
+ String action, String outcome) {
+
+ // Navigate solely based on outcome, if we get a match
+ String viewId = (String) destinations.get(outcome);
+ if (viewId != null) {
+ UIViewRoot view = getViewHandler(context).createView(context, viewId);
+ context.setViewRoot(view);
+ }
+
+ }
+
+
+ // --------------------------------------------------------- Private Methods
+
+
+ /**
+ * <p>Return the <code>ViewHandler</code> instance for this application.</p>
+ *
+ * @param context <code>FacesContext</code> for the current request
+ */
+ private ViewHandler getViewHandler(FacesContext context) {
+
+ return context.getApplication().getViewHandler();
+
+ }
+
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletContext.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletContext.java
new file mode 100644
index 0000000..fcd24a8
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletContext.java
@@ -0,0 +1,326 @@
+/*
+ * 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.shale.test.mock;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.portlet.PortletContext;
+import javax.portlet.PortletRequestDispatcher;
+
+/**
+ * <p>Mock implementation of <code>PortletContext</code>.</p>
+ *
+ * $Id$
+ */
+public class MockPortletContext implements PortletContext {
+
+ // ----------------------------------------------------- Mock Object Methods
+
+ /**
+ * <p>Add a context initialization parameter to the set of parameters
+ * recognized by this instance.</p>
+ *
+ * @param name Parameter name
+ * @param value Parameter value
+ */
+ public void addInitParameter(String name, String value) {
+
+ parameters.put(name, value);
+
+ }
+
+
+ /**
+ * <p>Add a new MIME type mapping to the set of mappings recognized by this
+ * instance.</p>
+ *
+ * @param extension Extension to check for (without the period)
+ * @param contentType Corresponding content type
+ */
+ public void addMimeType(String extension, String contentType) {
+
+ mimeTypes.put(extension, contentType);
+
+ }
+
+
+ /**
+ * <p>Set the document root for <code>getRealPath()</code> resolution.
+ * This parameter <strong>MUST</strong> represent a directory.</p>
+ *
+ * @param documentRoot The new base directory
+ */
+ public void setDocumentRoot(File documentRoot) {
+
+ this.documentRoot = documentRoot;
+
+ }
+
+ // ------------------------------------------------------ Instance Variables
+
+ private Hashtable attributes = new Hashtable();
+ private File documentRoot = null;
+ private Hashtable mimeTypes = new Hashtable();
+ private Hashtable parameters = new Hashtable();
+
+
+ // -------------------------------------------------- PortletContext Methods
+
+
+ /** {@inheritDoc} */
+ public Object getAttribute(String name) {
+
+ return attributes.get(name);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getAttributeNames() {
+
+ return attributes.keys();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getInitParameter(String name) {
+
+ return (String) parameters.get(name);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getInitParameterNames() {
+
+ return parameters.keys();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getMajorVersion() {
+
+ return 1;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getMimeType(String path) {
+
+ int period = path.lastIndexOf('.');
+ if (period < 0) {
+ return null;
+ }
+ String extension = path.substring(period + 1);
+ return (String) mimeTypes.get(extension);
+
+ }
+
+
+ public int getMinorVersion() {
+
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public PortletRequestDispatcher getNamedDispatcher(String arg0) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getPortletContextName() {
+
+ return "MockPortletContext";
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRealPath(String path) {
+
+ if (documentRoot != null) {
+ if (!path.startsWith("/")) {
+ throw new IllegalArgumentException("The specified path ('"
+ + path + "') does not start with a '/' character");
+ }
+ File resolved = new File(documentRoot, path.substring(1));
+ try {
+ return resolved.getCanonicalPath();
+ } catch (IOException e) {
+ return resolved.getAbsolutePath();
+ }
+ } else {
+ return null;
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public PortletRequestDispatcher getRequestDispatcher(String arg0) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public URL getResource(String path) throws MalformedURLException {
+
+ if (documentRoot != null) {
+ if (!path.startsWith("/")) {
+ throw new MalformedURLException("The specified path ('" + path
+ + "') does not start with a '/' character");
+ }
+ File resolved = new File(documentRoot, path.substring(1));
+ if (resolved.exists()) {
+ return resolved.toURL();
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public InputStream getResourceAsStream(String path) {
+
+ try {
+ URL url = getResource(path);
+ if (url != null) {
+ return url.openStream();
+ }
+ } catch (Exception e) {
+ ;
+ }
+ return null;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Set getResourcePaths(String path) {
+
+ if (documentRoot == null) {
+ return null;
+ }
+
+ // Enforce the leading slash restriction
+ if (!path.startsWith("/")) {
+ throw new IllegalArgumentException("The specified path ('" + path
+ + "') does not start with a '/' character");
+ }
+
+ // Locate the File node for this path's directory (if it exists)
+ File node = new File(documentRoot, path.substring(1));
+ if (!node.exists()) {
+ return null;
+ }
+ if (!node.isDirectory()) {
+ return null;
+ }
+
+ // Construct a Set containing the paths to the contents of this
+ // directory
+ Set set = new HashSet();
+ String[] files = node.list();
+ if (files == null) {
+ return null;
+ }
+ for (int i = 0; i < files.length; i++) {
+ String subfile = path + files[i];
+ File subnode = new File(node, files[i]);
+ if (subnode.isDirectory()) {
+ subfile += "/";
+ }
+ set.add(subfile);
+ }
+
+ // Return the completed set
+ return set;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getServerInfo() {
+
+ return "MockPortletContext";
+ }
+
+
+ /** {@inheritDoc} */
+ public void log(String message) {
+
+ System.out.println(message);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void log(String message, Throwable exception) {
+
+ System.out.println(message);
+ exception.printStackTrace();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void removeAttribute(String name) {
+
+ if (attributes.containsKey(name)) {
+ attributes.remove(name);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setAttribute(String name, Object value) {
+
+ if (name == null) {
+ throw new IllegalArgumentException("Attribute name cannot be null");
+ }
+ if (value == null) {
+ removeAttribute(name);
+ return;
+ }
+ attributes.put(name, value);
+
+ }
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletRequest.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletRequest.java
new file mode 100644
index 0000000..83c96b5
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletRequest.java
@@ -0,0 +1,421 @@
+/*
+ * 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.shale.test.mock;
+
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.portlet.PortalContext;
+import javax.portlet.PortletMode;
+import javax.portlet.PortletPreferences;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletSession;
+import javax.portlet.WindowState;
+
+/**
+ * <p> Mock implementation of <code>PortletRequest</code>. </p>
+ *
+ * $Id$
+ */
+
+public class MockPortletRequest implements PortletRequest {
+
+ // ------------------------------------------------------------ Constructors
+
+ public MockPortletRequest() {
+
+ super();
+
+ }
+
+
+ public MockPortletRequest(PortletSession session) {
+
+ super();
+ this.session = session;
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+ /**
+ * <p> Add a request parameter for this request. </p>
+ *
+ * @param name Parameter name
+ * @param value Parameter value
+ */
+ public void addParameter(String name, String value) {
+
+ String[] values = (String[]) parameters.get(name);
+ if (values == null) {
+ String[] results = new String[] { value };
+ parameters.put(name, results);
+ return;
+ }
+ String[] results = new String[values.length + 1];
+ System.arraycopy(values, 0, results, 0, values.length);
+ results[values.length] = value;
+ parameters.put(name, results);
+
+ }
+
+
+ /**
+ * <p> Set the <code>PortletSession</code> associated with this request.
+ * </p>
+ *
+ * @param session The new session
+ */
+ public void setPortletSession(PortletSession session) {
+
+ this.session = session;
+ }
+
+
+ /**
+ * <p> Set the <code>Locale</code> associated with this request. </p>
+ *
+ * @param locale The new locale
+ */
+ public void setLocale(Locale locale) {
+
+ this.locale = locale;
+
+ }
+
+
+ /**
+ * <p> Set the <code>Principal</code> associated with this request. </p>
+ *
+ * @param principal The new Principal
+ */
+ public void setUserPrincipal(Principal principal) {
+
+ this.principal = principal;
+
+ }
+
+ // ------------------------------------------------------ Instance Variables
+
+ private Map attributes = new HashMap();
+ private String contextPath = null;
+ private Locale locale = null;
+ private Map parameters = new HashMap();
+ private Principal principal = null;
+ private PortletSession session = null;
+
+
+ // -------------------------------------------------- PortletRequest Methods
+
+
+ /** {@inheritDoc} */
+ public String getAuthType() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getContextPath() {
+
+ return contextPath;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object getAttribute(String name) {
+
+ return attributes.get(name);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getAttributeNames() {
+
+ return new MockEnumeration(attributes.keySet().iterator());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Locale getLocale() {
+
+ return locale;
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getLocales() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getParameter(String name) {
+
+ String[] values = (String[]) parameters.get(name);
+ if (values != null) {
+ return values[0];
+ } else {
+ return null;
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Map getParameterMap() {
+
+ return parameters;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getParameterNames() {
+
+ return new MockEnumeration(parameters.keySet().iterator());
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String[] getParameterValues(String name) {
+
+ return (String[]) parameters.get(name);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public PortalContext getPortalContext() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public PortletMode getPortletMode() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public PortletSession getPortletSession() {
+
+ return getPortletSession(true);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public PortletSession getPortletSession(boolean create) {
+
+ if (create && (session == null)) {
+ throw new UnsupportedOperationException();
+ }
+ return session;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public PortletPreferences getPreferences() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getProperties(String arg0) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getProperty(String arg0) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getPropertyNames() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRemoteUser() {
+
+ if (principal != null) {
+ return principal.getName();
+ } else {
+ return null;
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getRequestedSessionId() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getResponseContentType() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getResponseContentTypes() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getScheme() {
+
+ return ("http");
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String getServerName() {
+
+ return ("localhost");
+
+ }
+
+
+ /** {@inheritDoc} */
+ public int getServerPort() {
+
+ return (8080);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Principal getUserPrincipal() {
+
+ return principal;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public WindowState getWindowState() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isPortletModeAllowed(PortletMode arg0) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isRequestedSessionIdValid() {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isSecure() {
+
+ return false;
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isUserInRole(String arg0) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public boolean isWindowStateAllowed(WindowState arg0) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void removeAttribute(String name) {
+
+ if (attributes.containsKey(name)) {
+ attributes.remove(name);
+ }
+
+ }
+
+
+ /** {@inheritDoc} */
+ public void setAttribute(String name, Object value) {
+
+ if (name == null) {
+ throw new IllegalArgumentException("Attribute name cannot be null");
+ }
+ if (value == null) {
+ removeAttribute(name);
+ return;
+ }
+ attributes.put(name, value);
+
+ }
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletResponse.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletResponse.java
new file mode 100644
index 0000000..b3ae1ea
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletResponse.java
@@ -0,0 +1,62 @@
+/*
+ * 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.shale.test.mock;
+
+import javax.portlet.PortletResponse;
+
+/**
+ * <p>Mock implementation of <code>PortletResponse</code>.</p>
+ *
+ * $Id$
+ */
+
+public class MockPortletResponse implements PortletResponse {
+
+ /**
+ * <p>Return a default instance.</p>
+ */
+ public MockPortletResponse() {
+
+ }
+
+
+ // -------------------------------------------------- PortletContext Methods
+
+ /** {@inheritDoc} */
+ public void addProperty(String name, String value) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+
+ /** {@inheritDoc} */
+ public String encodeURL(String url) {
+
+ return url;
+ }
+
+
+ /** {@inheritDoc} */
+ public void setProperty(String name, String value) {
+
+ throw new UnsupportedOperationException();
+
+ }
+
+}
diff --git a/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletSession.java b/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletSession.java
new file mode 100644
index 0000000..96d182b
--- /dev/null
+++ b/shale-test/src/main/java/org/apache/shale/test/mock/MockPortletSession.java
@@ -0,0 +1,268 @@
+/*
+ * 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.shale.test.mock;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.portlet.PortletContext;
+import javax.portlet.PortletSession;
+
+/**
+ * <p> Mock implementation of <code>PortletSession</code>. </p>
+ *
+ * $Id$
+ */
+public class MockPortletSession implements PortletSession {
+
+ // ------------------------------------------------------------ Constructors
+
+ /**
+ * <p> Configure a default instance. </p>
+ */
+ public MockPortletSession() {
+
+ super();
+
+ }
+
+
+ /**
+ * <p> Configure a session instance associated with the specified servlet
+ * context. </p>
+ *
+ * @param servletContext The associated servlet context
+ */
+ public MockPortletSession(PortletContext portletContext) {
+
+ super();
+ this.portletContext = portletContext;
+
+ }
+
+
+ // ----------------------------------------------------- Mock Object Methods
+
+ /**
+ * <p> Set the <code>PortletContext</code> associated with this session.
+ * </p>
+ *
+ * @param servletContext The associated servlet context
+ */
+ public void setPortletContext(PortletContext portletContext) {
+
+ this.portletContext = portletContext;
+
+ }
+
+ // ------------------------------------------------------ Instance Variables
+
+ private Map portletAttributes = new HashMap();
+ private Map applicationAttributes = new HashMap();
+ private String id = "123";
+ private PortletContext portletContext = null;
+
+
+ // ---------------------------------------------------------- Public Methods
+
+ /**
+ * <p> Set the session identifier of this session. </p>
+ *
+ * @param id The new session identifier
+ */
+ public void setId(String id) {
+
+ this.id = id;
+
+ }
+
+
+ // -------------------------------------------------- PortletSession Methods
+
+
+ /** {@inheritDoc} */
+ public Object getAttribute(String name) {
+
+ return getAttribute(name, PORTLET_SCOPE);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Object getAttribute(String name, int scope) {
+
+ if (scope == PORTLET_SCOPE) {
+ return portletAttributes.get(name);
+ } else if (scope == APPLICATION_SCOPE) {
+ return applicationAttributes.get(name);
+ }
+
+ throw new IllegalArgumentException("Scope constant " + scope
+ + " not recognized");
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getAttributeNames() {
+
+ return getAttributeNames(PORTLET_SCOPE);
+
+ }
+
+
+ /** {@inheritDoc} */
+ public Enumeration getAttributeNames(int scope) {
+
+ if (scope == PORTLET_SCOPE) {
+ return new MockEnumeration(portletAttributes.keySet().iterator());
+ } else if (scope == APPLICATION_SCOPE) {
+ return new MockEnumeration(applicationAttributes.keySet()
+ .iterator());
+ }
+
+ throw new IllegalArgumentException("Scope constant " + scope
+ + " not recognized");
+
+ }
+
... 6108 lines suppressed ...
--
To stop receiving notification emails like this one, please contact
deki@apache.org.