[seam-commits] Seam SVN: r13588 - in branches/enterprise/JBPAPP_4_3_FP01/src: main/org/jboss/seam/navigation and 1 other directories.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Tue Aug 10 04:51:39 EDT 2010


Author: manaRH
Date: 2010-08-10 04:51:38 -0400 (Tue, 10 Aug 2010)
New Revision: 13588

Added:
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/DelegatingServletInputStream.java
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/DelegatingServletOutputStream.java
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/EnhancedMockHttpServletRequest.java
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/EnhancedMockHttpServletResponse.java
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/HeaderValueHolder.java
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/MockRequestDispatcher.java
   branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/AbstractPageTest.java
Modified:
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/MockExternalContext.java
   branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/navigation/Pages.java
   branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/PageParamTest.java
Log:
JBPAPP-4774, JBPAPP-4686

Added: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/DelegatingServletInputStream.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/DelegatingServletInputStream.java	                        (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/DelegatingServletInputStream.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.seam.mock;
+
+import javax.servlet.ServletInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Delegating implementation of {@link javax.servlet.ServletInputStream}.
+ * <p/>
+ * <p>Used by {@link MockHttpServletRequest}; typically not directly
+ * used for testing application controllers.
+ *
+ * @author Juergen Hoeller
+ * @see MockHttpServletRequest
+ * @since 1.0.2
+ */
+public class DelegatingServletInputStream extends ServletInputStream
+{
+
+   private final InputStream sourceStream;
+
+
+   /**
+    * Create a DelegatingServletInputStream for the given source stream.
+    *
+    * @param sourceStream the source stream (never <code>null</code>)
+    */
+   public DelegatingServletInputStream(InputStream sourceStream)
+   {
+      this.sourceStream = sourceStream;
+   }
+
+   /**
+    * Return the underlying source stream (never <code>null</code>).
+    */
+   public final InputStream getSourceStream()
+   {
+      return this.sourceStream;
+   }
+
+
+   public int read() throws IOException
+   {
+      return this.sourceStream.read();
+   }
+
+   public void close() throws IOException
+   {
+      super.close();
+      this.sourceStream.close();
+	}
+
+}
\ No newline at end of file

Added: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/DelegatingServletOutputStream.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/DelegatingServletOutputStream.java	                        (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/DelegatingServletOutputStream.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.seam.mock;
+
+import javax.servlet.ServletOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+
+/**
+ * Delegating implementation of {@link javax.servlet.ServletOutputStream}.
+ * <p/>
+ * <p>Used by {@link MockHttpServletResponse}; typically not directly
+ * used for testing application controllers.
+ *
+ * @author Juergen Hoeller
+ * @see MockHttpServletResponse
+ * @since 1.0.2
+ */
+public class DelegatingServletOutputStream extends ServletOutputStream
+{
+
+   private final OutputStream targetStream;
+
+
+   /**
+    * Create a DelegatingServletOutputStream for the given target stream.
+    *
+    * @param targetStream the target stream (never <code>null</code>)
+    */
+   public DelegatingServletOutputStream(OutputStream targetStream)
+   {
+      this.targetStream = targetStream;
+   }
+
+   /**
+    * Return the underlying target stream (never <code>null</code>).
+    */
+   public final OutputStream getTargetStream()
+   {
+      return this.targetStream;
+   }
+
+
+   public void write(int b) throws IOException
+   {
+      this.targetStream.write(b);
+   }
+
+   public void flush() throws IOException
+   {
+      super.flush();
+      this.targetStream.flush();
+   }
+
+   public void close() throws IOException
+   {
+      super.close();
+      this.targetStream.close();
+   }
+
+}
\ No newline at end of file

Added: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/EnhancedMockHttpServletRequest.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/EnhancedMockHttpServletRequest.java	                        (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/EnhancedMockHttpServletRequest.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -0,0 +1,1093 @@
+/*
+ * Copyright 2002-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.seam.mock;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+/**
+ * Mock implementation of the {@link javax.servlet.http.HttpServletRequest}
+ * interface. Supports the Servlet 2.4 API level.
+ * <p/>
+ * <p>Used for testing the web framework; also useful for testing
+ * application controllers.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @author Rick Evans
+ * @author Mark Fisher
+ * @since 1.0.2
+ */
+public class EnhancedMockHttpServletRequest implements HttpServletRequest
+{
+
+   /**
+    * The default protocol: 'http'.
+    */
+   public static final String DEFAULT_PROTOCOL = "http";
+
+   /**
+    * The default server address: '127.0.0.1'.
+    */
+   public static final String DEFAULT_SERVER_ADDR = "127.0.0.1";
+
+   /**
+    * The default server name: 'localhost'.
+    */
+   public static final String DEFAULT_SERVER_NAME = "localhost";
+
+   /**
+    * The default server port: '80'.
+    */
+   public static final int DEFAULT_SERVER_PORT = 80;
+
+   /**
+    * The default remote address: '127.0.0.1'.
+    */
+   public static final String DEFAULT_REMOTE_ADDR = "127.0.0.1";
+
+   /**
+    * The default remote host: 'localhost'.
+    */
+   public static final String DEFAULT_REMOTE_HOST = "localhost";
+
+   private boolean active = true;
+
+
+   //---------------------------------------------------------------------
+   // ServletRequest properties
+   //---------------------------------------------------------------------
+
+   private final Hashtable attributes = new Hashtable();
+
+   private String characterEncoding;
+
+   private byte[] content;
+
+   private String contentType;
+
+   private final Map parameters = new LinkedHashMap(16);
+
+   private String protocol = DEFAULT_PROTOCOL;
+
+   private String scheme = DEFAULT_PROTOCOL;
+
+   private String serverName = DEFAULT_SERVER_NAME;
+
+   private int serverPort = DEFAULT_SERVER_PORT;
+
+   private String remoteAddr = DEFAULT_REMOTE_ADDR;
+
+   private String remoteHost = DEFAULT_REMOTE_HOST;
+
+   /**
+    * List of locales in descending order
+    */
+   private final Vector locales = new Vector();
+
+   private boolean secure = false;
+
+   private final ServletContext servletContext;
+
+   private int remotePort = DEFAULT_SERVER_PORT;
+
+   private String localName = DEFAULT_SERVER_NAME;
+
+   private String localAddr = DEFAULT_SERVER_ADDR;
+
+   private int localPort = DEFAULT_SERVER_PORT;
+
+
+   //---------------------------------------------------------------------
+   // HttpServletRequest properties
+   //---------------------------------------------------------------------
+
+   private String authType;
+
+   private Cookie[] cookies;
+
+   /**
+    * The key is the lowercase header name; the value is a {@link org.jboss.seam.mock.HeaderValueHolder} object.
+    */
+   private final Hashtable headers = new Hashtable();
+
+   private String method;
+
+   private String pathInfo;
+
+   private String contextPath = "";
+
+   private String queryString;
+
+   private Map<String, String> queryParameters = new HashMap();
+
+   private String remoteUser;
+
+   private Set<String> userRoles = new HashSet();
+
+   private Principal userPrincipal;
+
+   private String requestURI;
+
+   private String servletPath = "";
+
+   private HttpSession session;
+
+   private boolean requestedSessionIdValid = true;
+
+   private boolean requestedSessionIdFromCookie = true;
+
+   private boolean requestedSessionIdFromURL = false;
+
+
+   //---------------------------------------------------------------------
+   // Constructors
+   //---------------------------------------------------------------------
+
+   /**
+    * Create a new MockHttpServletRequest with a default
+    * {@link MockServletContext}.
+    *
+    * @see MockServletContext
+    */
+   public EnhancedMockHttpServletRequest()
+   {
+      this(null, "", "");
+   }
+
+   /**
+    * Create a new MockHttpServletRequest with a default
+    * {@link MockServletContext}.
+    *
+    * @param method     the request method (may be <code>null</code>)
+    * @param requestURI the request URI (may be <code>null</code>)
+    * @see #setMethod
+    * @see #setRequestURI
+    * @see MockServletContext
+    */
+   public EnhancedMockHttpServletRequest(String method, String requestURI)
+   {
+      this(null, method, requestURI);
+   }
+
+   /**
+    * Create a new MockHttpServletRequest.
+    *
+    * @param servletContext the ServletContext that the request runs in
+    *                       (may be <code>null</code> to use a default MockServletContext)
+    * @see MockServletContext
+    */
+   public EnhancedMockHttpServletRequest(ServletContext servletContext)
+   {
+      this(servletContext, "", "");
+   }
+
+   /**
+    * Create a new MockHttpServletRequest.
+    *
+    * @param servletContext the ServletContext that the request runs in
+    *                       (may be <code>null</code> to use a default MockServletContext)
+    * @param method         the request method (may be <code>null</code>)
+    * @param requestURI     the request URI (may be <code>null</code>)
+    * @see #setMethod
+    * @see #setRequestURI
+    * @see MockServletContext
+    */
+   public EnhancedMockHttpServletRequest(ServletContext servletContext, String method, String requestURI)
+   {
+      this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
+      this.method = method;
+      this.requestURI = requestURI;
+      this.locales.add(Locale.ENGLISH);
+
+      // Old mock: The 1.2 RI NPEs if this header isn't present
+      addHeader("Accept", new String[0]);
+   }
+
+
+   // OLD CONSTRUCTORS FROM < SEAM 2.2 MOCKS!
+
+   public EnhancedMockHttpServletRequest(HttpSession session)
+   {
+      this(session, null, new HashSet<String>());
+   }
+
+   public EnhancedMockHttpServletRequest(HttpSession session, String principalName, Set<String> principalRoles)
+   {
+      this(session, principalName, principalRoles, new Cookie[]{}, null);
+   }
+
+   public EnhancedMockHttpServletRequest(HttpSession session, final String principalName, Set<String> principalRoles, Cookie[] cookies, String method)
+   {
+      this(null, method, "");
+      this.session = session;
+
+      this.userPrincipal = principalName == null
+            ? null
+            : new Principal()
+      {
+         public String getName()
+         {
+            return principalName;
+         }
+      };
+
+      this.userRoles = principalRoles;
+      this.cookies = cookies;
+
+      // Old mock: The 1.2 RI NPEs if this header isn't present
+      addHeader("Accept", new String[0]);
+   }
+
+
+   //---------------------------------------------------------------------
+   // Lifecycle methods
+   //---------------------------------------------------------------------
+
+   /**
+    * Return the ServletContext that this request is associated with.
+    * (Not available in the standard HttpServletRequest interface for some reason.)
+    */
+   public ServletContext getServletContext()
+   {
+      return this.servletContext;
+   }
+
+   /**
+    * Return whether this request is still active (that is, not completed yet).
+    */
+   public boolean isActive()
+   {
+      return this.active;
+   }
+
+   /**
+    * Mark this request as completed, keeping its state.
+    */
+   public void close()
+   {
+      this.active = false;
+   }
+
+   /**
+    * Invalidate this request, clearing its state.
+    */
+   public void invalidate()
+   {
+      close();
+      clearAttributes();
+   }
+
+   /**
+    * Check whether this request is still active (that is, not completed yet),
+    * throwing an IllegalStateException if not active anymore.
+    */
+   protected void checkActive() throws IllegalStateException
+   {
+      if (!this.active)
+      {
+         throw new IllegalStateException("Request is not active anymore");
+      }
+   }
+
+
+   //---------------------------------------------------------------------
+   // ServletRequest interface
+   //---------------------------------------------------------------------
+
+   public Object getAttribute(String name)
+   {
+      checkActive();
+      return this.attributes.get(name);
+   }
+
+   public Enumeration getAttributeNames()
+   {
+      checkActive();
+      return this.attributes.keys();
+   }
+
+   public String getCharacterEncoding()
+   {
+      return this.characterEncoding;
+   }
+
+   public void setCharacterEncoding(String characterEncoding)
+   {
+      this.characterEncoding = characterEncoding;
+   }
+
+   public void setContent(byte[] content)
+   {
+      this.content = content;
+   }
+
+   public int getContentLength()
+   {
+      return (this.content != null ? this.content.length : -1);
+   }
+
+   public void setContentType(String contentType)
+   {
+      this.contentType = contentType;
+   }
+
+   public String getContentType()
+   {
+      return this.contentType;
+   }
+
+   public ServletInputStream getInputStream() throws IOException
+   {
+      if (this.content != null)
+      {
+         return new DelegatingServletInputStream(new ByteArrayInputStream(this.content));
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   /**
+    * Set a single value for the specified HTTP parameter.
+    * <p>If there are already one or more values registered for the given
+    * parameter name, they will be replaced.
+    */
+   public void setParameter(String name, String value)
+   {
+      setParameter(name, new String[]{value});
+   }
+
+   /**
+    * Set an array of values for the specified HTTP parameter.
+    * <p>If there are already one or more values registered for the given
+    * parameter name, they will be replaced.
+    */
+   public void setParameter(String name, String[] values)
+   {
+      this.parameters.put(name, values);
+   }
+
+   /**
+    * Sets all provided parameters <emphasis>replacing</emphasis> any
+    * existing values for the provided parameter names. To add without
+    * replacing existing values, use {@link #addParameters(java.util.Map)}.
+    */
+   public void setParameters(Map params)
+   {
+      for (Iterator it = params.keySet().iterator(); it.hasNext();)
+      {
+         Object key = it.next();
+         Object value = params.get(key);
+         if (value instanceof String)
+         {
+            this.setParameter((String) key, (String) value);
+         }
+         else if (value instanceof String[])
+         {
+            this.setParameter((String) key, (String[]) value);
+         }
+         else
+         {
+            throw new IllegalArgumentException("Parameter map value must be single value " +
+                  " or array of type [" + String.class.getName() + "]");
+         }
+      }
+   }
+
+   /**
+    * Add a single value for the specified HTTP parameter.
+    * <p>If there are already one or more values registered for the given
+    * parameter name, the given value will be added to the end of the list.
+    */
+   public void addParameter(String name, String value)
+   {
+      addParameter(name, new String[]{value});
+   }
+
+   /**
+    * Add an array of values for the specified HTTP parameter.
+    * <p>If there are already one or more values registered for the given
+    * parameter name, the given values will be added to the end of the list.
+    */
+   public void addParameter(String name, String[] values)
+   {
+      String[] oldArr = (String[]) this.parameters.get(name);
+      if (oldArr != null)
+      {
+         String[] newArr = new String[oldArr.length + values.length];
+         System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
+         System.arraycopy(values, 0, newArr, oldArr.length, values.length);
+         this.parameters.put(name, newArr);
+      }
+      else
+      {
+         this.parameters.put(name, values);
+      }
+   }
+
+   /**
+    * Adds all provided parameters <emphasis>without</emphasis> replacing
+    * any existing values. To replace existing values, use
+    * {@link #setParameters(java.util.Map)}.
+    */
+   public void addParameters(Map params)
+   {
+      for (Iterator it = params.keySet().iterator(); it.hasNext();)
+      {
+         Object key = it.next();
+         Object value = params.get(key);
+         if (value instanceof String)
+         {
+            this.addParameter((String) key, (String) value);
+         }
+         else if (value instanceof String[])
+         {
+            this.addParameter((String) key, (String[]) value);
+         }
+         else
+         {
+            throw new IllegalArgumentException("Parameter map value must be single value " +
+                  " or array of type [" + String.class.getName() + "]");
+         }
+      }
+   }
+
+   /**
+    * Remove already registered values for the specified HTTP parameter, if any.
+    */
+   public void removeParameter(String name)
+   {
+      this.parameters.remove(name);
+   }
+
+   /**
+    * Removes all existing parameters.
+    */
+   public void removeAllParameters()
+   {
+      this.parameters.clear();
+   }
+
+   public String getParameter(String name)
+   {
+      String[] arr = (String[]) this.parameters.get(name);
+      return (arr != null && arr.length > 0 ? arr[0] : null);
+   }
+
+   public Enumeration getParameterNames()
+   {
+      return Collections.enumeration(this.parameters.keySet());
+   }
+
+   public String[] getParameterValues(String name)
+   {
+      return (String[]) this.parameters.get(name);
+   }
+
+   public Map getParameterMap()
+   {
+      return this.parameters;
+   }
+
+   // Old mock
+   public Map<String, String[]> getParameters()
+   {
+      return parameters;
+   }
+
+   /**
+    * Add a query parameter that will be appended to the URI query string.
+    */
+   public void addQueryParameter(String name, String value)
+   {
+      addParameter(name, value);
+      this.queryParameters.put(name, value);
+   }
+
+   public void removeQueryParameter(String name)
+   {
+      removeParameter(name);
+      this.queryParameters.remove(name);
+   }
+
+   public Map<String, String> getQueryParameters()
+   {
+      return queryParameters;
+   }
+
+   public void setProtocol(String protocol)
+   {
+      this.protocol = protocol;
+   }
+
+   public String getProtocol()
+   {
+      return this.protocol;
+   }
+
+   public void setScheme(String scheme)
+   {
+      this.scheme = scheme;
+   }
+
+   public String getScheme()
+   {
+      return this.scheme;
+   }
+
+   public void setServerName(String serverName)
+   {
+      this.serverName = serverName;
+   }
+
+   public String getServerName()
+   {
+      return this.serverName;
+   }
+
+   public void setServerPort(int serverPort)
+   {
+      this.serverPort = serverPort;
+   }
+
+   public int getServerPort()
+   {
+      return this.serverPort;
+   }
+
+   public BufferedReader getReader() throws UnsupportedEncodingException
+   {
+      if (this.content != null)
+      {
+         InputStream sourceStream = new ByteArrayInputStream(this.content);
+         Reader sourceReader = (this.characterEncoding != null) ?
+               new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream);
+         return new BufferedReader(sourceReader);
+      }
+      else
+      {
+         return null;
+      }
+   }
+
+   public void setRemoteAddr(String remoteAddr)
+   {
+      this.remoteAddr = remoteAddr;
+   }
+
+   public String getRemoteAddr()
+   {
+      return this.remoteAddr;
+   }
+
+   public void setRemoteHost(String remoteHost)
+   {
+      this.remoteHost = remoteHost;
+   }
+
+   public String getRemoteHost()
+   {
+      return this.remoteHost;
+   }
+
+   public void setAttribute(String name, Object value)
+   {
+      checkActive();
+      if (value != null)
+      {
+         this.attributes.put(name, value);
+      }
+      else
+      {
+         this.attributes.remove(name);
+      }
+   }
+
+   public void removeAttribute(String name)
+   {
+      checkActive();
+      this.attributes.remove(name);
+   }
+
+   /**
+    * Clear all of this request's attributes.
+    */
+   public void clearAttributes()
+   {
+      this.attributes.clear();
+   }
+
+   /**
+    * Add a new preferred locale, before any existing locales.
+    */
+   public void addPreferredLocale(Locale locale)
+   {
+      this.locales.add(0, locale);
+   }
+
+   public Locale getLocale()
+   {
+      return (Locale) this.locales.get(0);
+   }
+
+   public Enumeration getLocales()
+   {
+      return this.locales.elements();
+   }
+
+   public void setSecure(boolean secure)
+   {
+      this.secure = secure;
+   }
+
+   public boolean isSecure()
+   {
+      return this.secure;
+   }
+
+   public RequestDispatcher getRequestDispatcher(String path)
+   {
+      return new MockRequestDispatcher(path);
+   }
+
+   public String getRealPath(String path)
+   {
+      return this.servletContext.getRealPath(path);
+   }
+
+   public void setRemotePort(int remotePort)
+   {
+      this.remotePort = remotePort;
+   }
+
+   public int getRemotePort()
+   {
+      return this.remotePort;
+   }
+
+   public void setLocalName(String localName)
+   {
+      this.localName = localName;
+   }
+
+   public String getLocalName()
+   {
+      return this.localName;
+   }
+
+   public void setLocalAddr(String localAddr)
+   {
+      this.localAddr = localAddr;
+   }
+
+   public String getLocalAddr()
+   {
+      return this.localAddr;
+   }
+
+   public void setLocalPort(int localPort)
+   {
+      this.localPort = localPort;
+   }
+
+   public int getLocalPort()
+   {
+      return this.localPort;
+   }
+
+
+   //---------------------------------------------------------------------
+   // HttpServletRequest interface
+   //---------------------------------------------------------------------
+
+   public void setAuthType(String authType)
+   {
+      this.authType = authType;
+   }
+
+   public String getAuthType()
+   {
+      return this.authType;
+   }
+
+   public void setCookies(Cookie[] cookies)
+   {
+      this.cookies = cookies;
+   }
+
+   public Cookie[] getCookies()
+   {
+      return this.cookies;
+   }
+
+   public void addCookie(Cookie cookie)
+   {
+      this.cookies = new Cookie[this.cookies.length + 1];
+      this.cookies[this.cookies.length - 1] = cookie;
+   }
+
+   /**
+    * Add a header entry for the given name.
+    * <p>If there was no entry for that header name before,
+    * the value will be used as-is. In case of an existing entry,
+    * a String array will be created, adding the given value (more
+    * specifically, its toString representation) as further element.
+    * <p>Multiple values can only be stored as list of Strings,
+    * following the Servlet spec (see <code>getHeaders</code> accessor).
+    * As alternative to repeated <code>addHeader</code> calls for
+    * individual elements, you can use a single call with an entire
+    * array or Collection of values as parameter.
+    *
+    * @see #getHeaderNames
+    * @see #getHeader
+    * @see #getHeaders
+    * @see #getDateHeader
+    * @see #getIntHeader
+    */
+   public void addHeader(String name, Object value)
+   {
+      HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+      if (header == null)
+      {
+         header = new HeaderValueHolder();
+         this.headers.put(name, header);
+      }
+      if (value instanceof Collection)
+      {
+         header.addValues((Collection) value);
+      }
+      else if (value.getClass().isArray())
+      {
+         header.addValueArray(value);
+      }
+      else
+      {
+         header.addValue(value);
+      }
+   }
+
+   public long getDateHeader(String name)
+   {
+      HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+      Object value = (header != null ? header.getValue() : null);
+      if (value instanceof Date)
+      {
+         return ((Date) value).getTime();
+      }
+      else if (value instanceof Number)
+      {
+         return ((Number) value).longValue();
+      }
+      else if (value != null)
+      {
+         throw new IllegalArgumentException(
+               "Value for header '" + name + "' is neither a Date nor a Number: " + value);
+      }
+      else
+      {
+         return -1L;
+      }
+   }
+
+   public String getHeader(String name)
+   {
+      HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+      return (header != null ? header.getValue().toString() : null);
+   }
+
+   public Map<String, String[]> getHeaders()
+   {
+      Map<String, String[]> headerValues = new HashMap();
+
+      for (Object o : this.headers.entrySet())
+      {
+         Map.Entry<String, HeaderValueHolder> entry = (Map.Entry<String, HeaderValueHolder>)o;
+         String[] values = (String[])entry.getValue().getValues().toArray(new String[entry.getValue().getValues().size()]);
+         headerValues.put(entry.getKey(), values);
+      }
+
+      return headerValues;
+   }
+
+   public Enumeration getHeaders(String name)
+   {
+      HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+      return Collections.enumeration(header != null ? header.getValues() : Collections.EMPTY_LIST);
+   }
+
+   public Enumeration getHeaderNames()
+   {
+      return this.headers.keys();
+   }
+
+   public int getIntHeader(String name)
+   {
+      HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+      Object value = (header != null ? header.getValue() : null);
+      if (value instanceof Number)
+      {
+         return ((Number) value).intValue();
+      }
+      else if (value instanceof String)
+      {
+         return Integer.parseInt((String) value);
+      }
+      else if (value != null)
+      {
+         throw new NumberFormatException("Value for header '" + name + "' is not a Number: " + value);
+      }
+      else
+      {
+         return -1;
+      }
+   }
+
+   public void setMethod(String method)
+   {
+      this.method = method;
+   }
+
+   public String getMethod()
+   {
+      return this.method;
+   }
+
+   public void setPathInfo(String pathInfo)
+   {
+      this.pathInfo = pathInfo;
+   }
+
+   public String getPathInfo()
+   {
+      return this.pathInfo;
+   }
+
+   public String getPathTranslated()
+   {
+      return (this.pathInfo != null ? getRealPath(this.pathInfo) : null);
+   }
+
+   public void setContextPath(String contextPath)
+   {
+      this.contextPath = contextPath;
+   }
+
+   public String getContextPath()
+   {
+      return this.contextPath != null ? this.contextPath : "/project"; // Old mock default
+   }
+
+   public void setQueryString(String queryString)
+   {
+      this.queryString = queryString;
+   }
+
+   public String getQueryString()
+   {
+      if (getQueryParameters().size() > 0)
+      {
+         StringBuilder q = new StringBuilder(queryString);
+         if (!queryString.endsWith("&")) q.append("&");
+         for (Map.Entry<String, String> entry : getQueryParameters().entrySet())
+         {
+            q.append(entry.getKey());
+            q.append("=");
+            q.append(entry.getValue());
+            q.append("&");
+         }
+         if (q.toString().endsWith("&"))
+         {
+            q.deleteCharAt(q.length() - 1);
+         }
+         return q.toString();
+      }
+      return this.queryString;
+   }
+
+   public void setRemoteUser(String remoteUser)
+   {
+      this.remoteUser = remoteUser;
+   }
+
+   public String getRemoteUser()
+   {
+      return this.remoteUser;
+   }
+
+   /**
+    * @see #addUserRole
+    * @deprecated in favor of addUserRole
+    */
+   public void addRole(String role)
+   {
+      addUserRole(role);
+   }
+
+   public void addUserRole(String role)
+   {
+      this.userRoles.add(role);
+   }
+
+   public boolean isUserInRole(String role)
+   {
+      return this.userRoles.contains(role);
+   }
+
+   public void setUserPrincipal(Principal userPrincipal)
+   {
+      this.userPrincipal = userPrincipal;
+   }
+
+   public Principal getUserPrincipal()
+   {
+      return this.userPrincipal;
+   }
+
+   public String getRequestedSessionId()
+   {
+      HttpSession session = getSession();
+      return (session != null ? session.getId() : null);
+   }
+
+   public void setRequestURI(String requestURI)
+   {
+      this.requestURI = requestURI;
+   }
+
+   public String getRequestURI()
+   {
+      return this.requestURI;
+   }
+
+   public StringBuffer getRequestURL()
+   {
+      StringBuffer url = new StringBuffer(this.scheme);
+      url.append("://").append(this.serverName).append(':').append(this.serverPort);
+      url.append(getRequestURI());
+      return url;
+   }
+
+   public void setServletPath(String servletPath)
+   {
+      this.servletPath = servletPath;
+   }
+
+   public String getServletPath()
+   {
+      return this.servletPath;
+   }
+
+   public void setSession(HttpSession session)
+   {
+      /*
+	   TODO: We don't track access times in mocks (yet) mockSession.access();
+		if (session instanceof MockHttpSession) {
+			MockHttpSession mockSession = ((MockHttpSession) session);
+			...
+		}
+		*/
+      this.session = session;
+   }
+
+   public HttpSession getSession(boolean create)
+   {
+      checkActive();
+      // Reset session if invalidated.
+      if (this.session instanceof MockHttpSession && ((MockHttpSession) this.session).isInvalid())
+      {
+         this.session = null;
+      }
+      // Create new session if necessary.
+      if (this.session == null && create)
+      {
+         this.session = new MockHttpSession(this.servletContext);
+      }
+      return this.session;
+   }
+
+   public HttpSession getSession()
+   {
+      return getSession(true);
+   }
+
+   public void setRequestedSessionIdValid(boolean requestedSessionIdValid)
+   {
+      this.requestedSessionIdValid = requestedSessionIdValid;
+   }
+
+   public boolean isRequestedSessionIdValid()
+   {
+      return this.requestedSessionIdValid;
+   }
+
+   public void setRequestedSessionIdFromCookie(boolean requestedSessionIdFromCookie)
+   {
+      this.requestedSessionIdFromCookie = requestedSessionIdFromCookie;
+   }
+
+   public boolean isRequestedSessionIdFromCookie()
+   {
+      return this.requestedSessionIdFromCookie;
+   }
+
+   public void setRequestedSessionIdFromURL(boolean requestedSessionIdFromURL)
+   {
+      this.requestedSessionIdFromURL = requestedSessionIdFromURL;
+   }
+
+   public boolean isRequestedSessionIdFromURL()
+   {
+      return this.requestedSessionIdFromURL;
+   }
+
+   public boolean isRequestedSessionIdFromUrl()
+   {
+      return isRequestedSessionIdFromURL();
+	}
+
+   public boolean isAllParametersInQueryString() {
+      return true;
+   }
+
+}
\ No newline at end of file

Added: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/EnhancedMockHttpServletResponse.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/EnhancedMockHttpServletResponse.java	                        (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/EnhancedMockHttpServletResponse.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2002-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.seam.mock;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * Mock implementation of the {@link javax.servlet.http.HttpServletResponse}
+ * interface. Supports the Servlet 2.4 API level.
+ *
+ * <p>Used for testing the web framework; also useful for testing
+ * application controllers.
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 1.0.2
+ */
+public class EnhancedMockHttpServletResponse implements HttpServletResponse {
+
+	public static final int DEFAULT_SERVER_PORT = 80;
+
+	private static final String CHARSET_PREFIX = "charset=";
+
+
+	//---------------------------------------------------------------------
+	// ServletResponse properties
+	//---------------------------------------------------------------------
+
+	private boolean outputStreamAccessAllowed = true;
+
+	private boolean writerAccessAllowed = true;
+
+	private String characterEncoding = "ISO-8859-1";
+
+	private final ByteArrayOutputStream content = new ByteArrayOutputStream();
+
+	private final ServletOutputStream outputStream = new ResponseServletOutputStream(this.content);
+
+	private PrintWriter writer;
+
+	private int contentLength = 0;
+
+	private String contentType;
+
+	private int bufferSize = 4096;
+
+	private boolean committed;
+
+	private Locale locale = Locale.getDefault();
+
+
+	//---------------------------------------------------------------------
+	// HttpServletResponse properties
+	//---------------------------------------------------------------------
+
+	private final List cookies = new ArrayList();
+
+	/**
+	 * The key is the lowercase header name; the value is a {@link org.jboss.seam.mock.HeaderValueHolder} object.
+	 */
+	private final Map headers = new HashMap();
+
+	private int status = HttpServletResponse.SC_OK;
+
+	private String statusMessage;
+
+	private String redirectedUrl;
+
+	private String forwardedUrl;
+
+	private String includedUrl;
+
+
+   //---------------------------------------------------------------------
+	// ServletResponse interface
+	//---------------------------------------------------------------------
+
+	/**
+	 * Set whether {@link #getOutputStream()} access is allowed.
+	 * <p>Default is <code>true</code>.
+	 */
+	public void setOutputStreamAccessAllowed(boolean outputStreamAccessAllowed) {
+		this.outputStreamAccessAllowed = outputStreamAccessAllowed;
+	}
+
+	/**
+	 * Return whether {@link #getOutputStream()} access is allowed.
+	 */
+	public boolean isOutputStreamAccessAllowed() {
+		return this.outputStreamAccessAllowed;
+	}
+
+	/**
+	 * Set whether {@link #getWriter()} access is allowed.
+	 * <p>Default is <code>true</code>.
+	 */
+	public void setWriterAccessAllowed(boolean writerAccessAllowed) {
+		this.writerAccessAllowed = writerAccessAllowed;
+	}
+
+	/**
+	 * Return whether {@link #getOutputStream()} access is allowed.
+	 */
+	public boolean isWriterAccessAllowed() {
+		return this.writerAccessAllowed;
+	}
+
+	public void setCharacterEncoding(String characterEncoding) {
+		this.characterEncoding = characterEncoding;
+	}
+
+	public String getCharacterEncoding() {
+		return this.characterEncoding;
+	}
+
+	public ServletOutputStream getOutputStream() {
+		if (!this.outputStreamAccessAllowed) {
+			throw new IllegalStateException("OutputStream access not allowed");
+		}
+		return this.outputStream;
+	}
+
+	public PrintWriter getWriter() throws UnsupportedEncodingException {
+		if (!this.writerAccessAllowed) {
+			throw new IllegalStateException("Writer access not allowed");
+		}
+		if (this.writer == null) {
+			Writer targetWriter = (this.characterEncoding != null ?
+					new OutputStreamWriter(this.content, this.characterEncoding) : new OutputStreamWriter(this.content));
+			this.writer = new ResponsePrintWriter(targetWriter);
+		}
+		return this.writer;
+	}
+
+	public byte[] getContentAsByteArray() {
+		flushBuffer();
+		return this.content.toByteArray();
+	}
+
+	public String getContentAsString() {
+		flushBuffer();
+      try {
+         return (this.characterEncoding != null) ?
+               this.content.toString(this.characterEncoding) : this.content.toString();
+      } catch (UnsupportedEncodingException ex) {
+         throw new RuntimeException(ex);
+      }
+	}
+
+	public void setContentLength(int contentLength) {
+		this.contentLength = contentLength;
+	}
+
+	public int getContentLength() {
+		return this.contentLength;
+	}
+
+	public void setContentType(String contentType) {
+		this.contentType = contentType;
+		if (contentType != null) {
+			int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX);
+			if (charsetIndex != -1) {
+				String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length());
+				setCharacterEncoding(encoding);
+			}
+		}
+	}
+
+	public String getContentType() {
+		return this.contentType;
+	}
+
+	public void setBufferSize(int bufferSize) {
+		this.bufferSize = bufferSize;
+	}
+
+	public int getBufferSize() {
+		return this.bufferSize;
+	}
+
+	public void flushBuffer() {
+		setCommitted(true);
+	}
+
+	public void resetBuffer() {
+		if (isCommitted()) {
+			throw new IllegalStateException("Cannot reset buffer - response is already committed");
+		}
+		this.content.reset();
+	}
+
+	private void setCommittedIfBufferSizeExceeded() {
+		int bufSize = getBufferSize();
+		if (bufSize > 0 && this.content.size() > bufSize) {
+			setCommitted(true);
+		}
+	}
+
+	public void setCommitted(boolean committed) {
+		this.committed = committed;
+	}
+
+	public boolean isCommitted() {
+		return this.committed;
+	}
+
+	public void reset() {
+		resetBuffer();
+		this.characterEncoding = null;
+		this.contentLength = 0;
+		this.contentType = null;
+		this.locale = null;
+		this.cookies.clear();
+		this.headers.clear();
+		this.status = HttpServletResponse.SC_OK;
+		this.statusMessage = null;
+	}
+
+	public void setLocale(Locale locale) {
+		this.locale = locale;
+	}
+
+	public Locale getLocale() {
+		return this.locale;
+	}
+
+
+	//---------------------------------------------------------------------
+	// HttpServletResponse interface
+	//---------------------------------------------------------------------
+
+	public void addCookie(Cookie cookie) {
+		this.cookies.add(cookie);
+	}
+
+	public Cookie[] getCookies() {
+		return (Cookie[]) this.cookies.toArray(new Cookie[this.cookies.size()]);
+	}
+
+	public Cookie getCookie(String name) {
+		for (Iterator it = this.cookies.iterator(); it.hasNext();) {
+			Cookie cookie = (Cookie) it.next();
+			if (name.equals(cookie.getName())) {
+				return cookie;
+			}
+		}
+		return null;
+	}
+
+	public boolean containsHeader(String name) {
+		return (HeaderValueHolder.getByName(this.headers, name) != null);
+	}
+
+	/**
+	 * Return the names of all specified headers as a Set of Strings.
+	 * @return the <code>Set</code> of header name <code>Strings</code>, or an empty <code>Set</code> if none
+	 */
+	public Set getHeaderNames() {
+		return this.headers.keySet();
+	}
+
+	/**
+	 * Return the primary value for the given header, if any.
+	 * <p>Will return the first value in case of multiple values.
+	 * @param name the name of the header
+	 * @return the associated header value, or <code>null<code> if none
+	 */
+	public Object getHeader(String name) {
+		HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+		return (header != null ? header.getValue() : null);
+	}
+
+	/**
+	 * Return all values for the given header as a List of value objects.
+	 * @param name the name of the header
+	 * @return the associated header values, or an empty List if none
+	 */
+	public List getHeaders(String name) {
+		HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+		return (header != null ? header.getValues() : Collections.EMPTY_LIST);
+	}
+
+	/**
+	 * The default implementation returns the given URL String as-is.
+	 * <p>Can be overridden in subclasses, appending a session id or the like.
+	 */
+	public String encodeURL(String url) {
+		return url;
+	}
+
+	/**
+	 * The default implementation delegates to {@link #encodeURL},
+	 * returning the given URL String as-is.
+	 * <p>Can be overridden in subclasses, appending a session id or the like
+	 * in a redirect-specific fashion. For general URL encoding rules,
+	 * override the common {@link #encodeURL} method instead, appyling
+	 * to redirect URLs as well as to general URLs.
+	 */
+	public String encodeRedirectURL(String url) {
+		return encodeURL(url);
+	}
+
+	public String encodeUrl(String url) {
+		return encodeURL(url);
+	}
+
+	public String encodeRedirectUrl(String url) {
+		return encodeRedirectURL(url);
+	}
+
+	public void sendError(int status, String errorMessage) throws IOException {
+		if (isCommitted()) {
+			throw new IllegalStateException("Cannot set error status - response is already committed");
+		}
+		this.status = status;
+		this.statusMessage = errorMessage;
+		setCommitted(true);
+	}
+
+	public void sendError(int status) throws IOException {
+		if (isCommitted()) {
+			throw new IllegalStateException("Cannot set error status - response is already committed");
+		}
+		this.status = status;
+		setCommitted(true);
+	}
+
+	public void sendRedirect(String url) throws IOException {
+		if (isCommitted()) {
+			throw new IllegalStateException("Cannot send redirect - response is already committed");
+		}
+		this.redirectedUrl = url;
+		setCommitted(true);
+	}
+
+	public String getRedirectedUrl() {
+		return this.redirectedUrl;
+	}
+
+	public void setDateHeader(String name, long value) {
+		setHeaderValue(name, new Long(value));
+	}
+
+	public void addDateHeader(String name, long value) {
+		addHeaderValue(name, new Long(value));
+	}
+
+	public void setHeader(String name, String value) {
+		setHeaderValue(name, value);
+	}
+
+	public void addHeader(String name, String value) {
+		addHeaderValue(name, value);
+	}
+
+	public void setIntHeader(String name, int value) {
+		setHeaderValue(name, new Integer(value));
+	}
+
+	public void addIntHeader(String name, int value) {
+		addHeaderValue(name, new Integer(value));
+	}
+
+	private void setHeaderValue(String name, Object value) {
+		doAddHeaderValue(name, value, true);
+	}
+
+	private void addHeaderValue(String name, Object value) {
+		doAddHeaderValue(name, value, false);
+	}
+
+	private void doAddHeaderValue(String name, Object value, boolean replace) {
+		HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
+		if (header == null) {
+			header = new HeaderValueHolder();
+			this.headers.put(name, header);
+		}
+		if (replace) {
+			header.setValue(value);
+		}
+		else {
+			header.addValue(value);
+		}
+	}
+
+	public void setStatus(int status) {
+		this.status = status;
+	}
+
+	public void setStatus(int status, String statusMessage) {
+		this.status = status;
+		this.statusMessage = statusMessage;
+	}
+
+	public int getStatus() {
+		return this.status;
+	}
+
+	public String getStatusMessage() {
+		return this.statusMessage;
+	}
+
+
+	//---------------------------------------------------------------------
+	// Methods for MockRequestDispatcher
+	//---------------------------------------------------------------------
+
+	public void setForwardedUrl(String forwardedUrl) {
+		this.forwardedUrl = forwardedUrl;
+	}
+
+	public String getForwardedUrl() {
+		return this.forwardedUrl;
+	}
+
+	public void setIncludedUrl(String includedUrl) {
+		this.includedUrl = includedUrl;
+	}
+
+	public String getIncludedUrl() {
+		return this.includedUrl;
+	}
+
+
+   /**
+	 * Inner class that adapts the ServletOutputStream to mark the
+	 * response as committed once the buffer size is exceeded.
+	 */
+	private class ResponseServletOutputStream extends DelegatingServletOutputStream
+   {
+
+		public ResponseServletOutputStream(OutputStream out) {
+			super(out);
+		}
+
+		public void write(int b) throws IOException {
+			super.write(b);
+			super.flush();
+			setCommittedIfBufferSizeExceeded();
+		}
+
+		public void flush() throws IOException {
+			super.flush();
+			setCommitted(true);
+		}
+	}
+
+
+	/**
+	 * Inner class that adapts the PrintWriter to mark the
+	 * response as committed once the buffer size is exceeded.
+	 */
+	private class ResponsePrintWriter extends PrintWriter {
+
+		public ResponsePrintWriter(Writer out) {
+			super(out, true);
+		}
+
+		public void write(char buf[], int off, int len) {
+			super.write(buf, off, len);
+			super.flush();
+			setCommittedIfBufferSizeExceeded();
+		}
+
+		public void write(String s, int off, int len) {
+			super.write(s, off, len);
+			super.flush();
+			setCommittedIfBufferSizeExceeded();
+		}
+
+		public void write(int c) {
+			super.write(c);
+			super.flush();
+			setCommittedIfBufferSizeExceeded();
+		}
+
+		public void flush() {
+			super.flush();
+			setCommitted(true);
+		}
+	}
+
+}
\ No newline at end of file

Added: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/HeaderValueHolder.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/HeaderValueHolder.java	                        (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/HeaderValueHolder.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.seam.mock;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Internal helper class that serves as value holder for request headers.
+ *
+ * @author Juergen Hoeller
+ * @author Rick Evans
+ * @since 2.0.1
+ */
+class HeaderValueHolder
+{
+
+   private final List values = new LinkedList();
+
+
+   public void setValue(Object value)
+   {
+      this.values.clear();
+      this.values.add(value);
+   }
+
+   public void addValue(Object value)
+   {
+      this.values.add(value);
+   }
+
+   public void addValues(Collection values)
+   {
+      this.values.addAll(values);
+   }
+
+   public void addValueArray(Object values)
+   {
+      Object[] arr = toObjectArray(values);
+      this.values.addAll(Arrays.asList(arr));
+   }
+
+   public List getValues()
+   {
+      return Collections.unmodifiableList(this.values);
+   }
+
+   public Object getValue()
+   {
+      return (!this.values.isEmpty() ? this.values.get(0) : null);
+   }
+
+
+   /**
+    * Find a HeaderValueHolder by name, ignoring casing.
+    *
+    * @param headers the Map of header names to HeaderValueHolders
+    * @param name    the name of the desired header
+    * @return the corresponding HeaderValueHolder,
+    *         or <code>null</code> if none found
+    */
+   public static HeaderValueHolder getByName(Map headers, String name)
+   {
+      for (Iterator it = headers.keySet().iterator(); it.hasNext();)
+      {
+         String headerName = (String) it.next();
+         if (headerName.equalsIgnoreCase(name))
+         {
+            return (HeaderValueHolder) headers.get(headerName);
+         }
+      }
+      return null;
+   }
+
+   public static Object[] toObjectArray(Object source)
+   {
+      if (source instanceof Object[])
+      {
+         return (Object[]) source;
+      }
+      if (source == null)
+      {
+         return new Object[0];
+      }
+      if (!source.getClass().isArray())
+      {
+         throw new IllegalArgumentException("Source is not an array: " + source);
+      }
+      int length = Array.getLength(source);
+      if (length == 0)
+      {
+         return new Object[0];
+      }
+      Class wrapperType = Array.get(source, 0).getClass();
+      Object[] newArray = (Object[]) Array.newInstance(wrapperType, length);
+      for (int i = 0; i < length; i++)
+      {
+         newArray[i] = Array.get(source, i);
+      }
+      return newArray;
+	}
+
+}
\ No newline at end of file

Modified: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/MockExternalContext.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/MockExternalContext.java	2010-08-10 08:26:30 UTC (rev 13587)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/MockExternalContext.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -520,7 +520,15 @@
       response.sendRedirect(url);
       FacesContext.getCurrentInstance().responseComplete();
    }
+   
+   
 
+   @Override
+   public void setRequest(Object myrequest)
+   {
+      this.request = (HttpServletRequest) myrequest;
+   }
+
    /**
     * @since 1.2
     */

Added: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/MockRequestDispatcher.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/MockRequestDispatcher.java	                        (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/mock/MockRequestDispatcher.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.seam.mock;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface.
+ * <p/>
+ * <p>Used for testing the web framework; typically not necessary for
+ * testing application controllers.
+ *
+ * @author Rod Johnson
+ * @author Juergen Hoeller
+ * @since 1.0.2
+ */
+public class MockRequestDispatcher implements RequestDispatcher
+{
+
+   private final Log logger = LogFactory.getLog(getClass());
+
+   private final String url;
+
+
+   /**
+    * Create a new MockRequestDispatcher for the given URL.
+    *
+    * @param url the URL to dispatch to.
+    */
+   public MockRequestDispatcher(String url)
+   {
+      this.url = url;
+   }
+
+
+   public void forward(ServletRequest request, ServletResponse response)
+   {
+      if (response.isCommitted())
+      {
+         throw new IllegalStateException("Cannot perform forward - response is already committed");
+      }
+      getMockHttpServletResponse(response).setForwardedUrl(this.url);
+      if (logger.isDebugEnabled())
+      {
+         logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]");
+      }
+   }
+
+   public void include(ServletRequest request, ServletResponse response)
+   {
+      getMockHttpServletResponse(response).setIncludedUrl(this.url);
+      if (logger.isDebugEnabled())
+      {
+         logger.debug("MockRequestDispatcher: including URL [" + this.url + "]");
+      }
+   }
+
+   /**
+    * Obtain the underlying EnhancedMockHttpServletResponse,
+    * unwrapping {@link javax.servlet.http.HttpServletResponseWrapper} decorators if necessary.
+    */
+   protected EnhancedMockHttpServletResponse getMockHttpServletResponse(ServletResponse response)
+   {
+      if (response instanceof EnhancedMockHttpServletResponse)
+      {
+         return (EnhancedMockHttpServletResponse) response;
+      }
+      if (response instanceof HttpServletResponseWrapper)
+      {
+         return getMockHttpServletResponse(((HttpServletResponseWrapper) response).getResponse());
+      }
+      throw new IllegalArgumentException("MockRequestDispatcher requires MockHttpServletResponse");
+	}
+
+}
\ No newline at end of file

Modified: branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/navigation/Pages.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/navigation/Pages.java	2010-08-10 08:26:30 UTC (rev 13587)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/main/org/jboss/seam/navigation/Pages.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -5,6 +5,7 @@
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -17,8 +18,8 @@
 import java.util.TreeSet;
 
 import javax.faces.application.FacesMessage;
+import javax.faces.application.FacesMessage.Severity;
 import javax.faces.application.ViewHandler;
-import javax.faces.application.FacesMessage.Severity;
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.FacesContext;
 import javax.faces.convert.ConverterException;
@@ -629,6 +630,16 @@
       String outcome = facesContext.getExternalContext()
             .getRequestParameterMap().get("actionOutcome");
       String fromAction = outcome;
+
+      String decodedOutcome = null;
+      if (outcome != null)
+      {
+         decodedOutcome = URLDecoder.decode(outcome);
+      }
+
+      if (decodedOutcome != null && (decodedOutcome.indexOf('#') >= 0 || decodedOutcome.indexOf('{') >= 0) ){
+         throw new IllegalArgumentException("EL expressions are not allowed in actionOutcome parameter");
+      }
       
       if (outcome==null)
       {

Added: branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/AbstractPageTest.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/AbstractPageTest.java	                        (rev 0)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/AbstractPageTest.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -0,0 +1,91 @@
+package org.jboss.seam.test.unit;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.Seam;
+import org.jboss.seam.contexts.Context;
+import org.jboss.seam.contexts.Contexts;
+import org.jboss.seam.contexts.FacesLifecycle;
+import org.jboss.seam.contexts.Lifecycle;
+import org.jboss.seam.core.Expressions;
+import org.jboss.seam.core.Init;
+import org.jboss.seam.core.Interpolator;
+import org.jboss.seam.core.Locale;
+import org.jboss.seam.core.ResourceLoader;
+import org.jboss.seam.mock.MockApplication;
+import org.jboss.seam.mock.MockExternalContext;
+import org.jboss.seam.mock.MockFacesContext;
+import org.jboss.seam.navigation.Pages;
+import org.jboss.seam.util.Conversions;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+
+/**
+ * Abstract class that provides the setup and tear-down necessary to initialize the context for performing tests
+ * against the Pages component.
+ */
+public abstract class AbstractPageTest
+{
+   private static final String TEST_PAGES_DOT_XML = "/META-INF/pagesForPageActionsTest.xml";
+   
+   @BeforeMethod
+   public void setup()
+   {
+      // create main application map
+      Lifecycle.beginApplication(new HashMap<String, Object>());
+
+      // start all the contexts
+      Lifecycle.beginCall();
+
+      // establish the FacesContext
+      new MockFacesContext(new MockExternalContext(), new MockApplication()).setCurrent().createViewRoot();
+      FacesLifecycle.resumePage();
+
+      // install key components
+      installComponents(Contexts.getApplicationContext());
+
+      // initialize pages
+      // the descriptor file locations are set using the property: org.jboss.seam.navigation.pages.resources
+      // this setup of this test sets this property value to: /META-INF/pagesForPageActionsTest.xml
+      Pages.instance();
+
+      // mark the application as started
+      Lifecycle.mockApplication();
+   }
+
+   @AfterMethod
+   public void tearDown()
+   {
+      Lifecycle.endApplication();
+      Lifecycle.unmockApplication();
+   }
+   
+   protected void installComponents(Context appContext)
+   {
+      Init init = new Init();
+      init.setTransactionManagementEnabled(false);
+      appContext.set(Seam.getComponentName(Init.class), init);
+      Map<String, Conversions.PropertyValue> properties = new HashMap<String, Conversions.PropertyValue>();
+      appContext.set(Component.PROPERTIES, properties);
+      properties.put(Seam.getComponentName(Pages.class) + ".resources", new Conversions.FlatPropertyValue(TEST_PAGES_DOT_XML));
+
+      installComponent(appContext, ResourceLoader.class);
+      installComponent(appContext, Expressions.class);
+      installComponent(appContext, Pages.class);
+      installComponent(appContext, Interpolator.class);
+      installComponent(appContext, Locale.class);
+   }
+
+   /**
+    * Installs a component for use in the current test context.
+    * 
+    * @param appContext
+    * @param clazz
+    */
+   protected void installComponent(Context appContext, Class clazz)
+   {
+      appContext.set(Seam.getComponentName(clazz) + ".component", new Component(clazz));
+   }
+}

Modified: branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/PageParamTest.java
===================================================================
--- branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/PageParamTest.java	2010-08-10 08:26:30 UTC (rev 13587)
+++ branches/enterprise/JBPAPP_4_3_FP01/src/test/unit/org/jboss/seam/test/unit/PageParamTest.java	2010-08-10 08:51:38 UTC (rev 13588)
@@ -6,13 +6,15 @@
 import javax.faces.validator.Validator;
 import javax.faces.validator.ValidatorException;
 
+import org.jboss.seam.mock.EnhancedMockHttpServletRequest;
 import org.jboss.seam.mock.MockApplication;
 import org.jboss.seam.mock.MockExternalContext;
 import org.jboss.seam.mock.MockFacesContext;
+import org.jboss.seam.navigation.Pages;
 import org.jboss.seam.navigation.Param;
 import org.testng.annotations.Test;
 
-public class PageParamTest
+public class PageParamTest extends AbstractPageTest
 {
    @Test
    public void testGetConverterById()
@@ -39,6 +41,27 @@
       assert param.getValidator() instanceof TestValidator : "expecting: " + validatorClass + "; got: " + param.getValidator();
    }
    
+   /**
+    * Verify EL expression disability in actionOutcome parameter
+    */
+   @Test(expectedExceptions = IllegalArgumentException.class )
+   public void testGetCallAction()
+   {
+      EnhancedMockHttpServletRequest request = new EnhancedMockHttpServletRequest();
+      request.addParameter("actionOutcome", "#{variable}");
+      FacesContext.getCurrentInstance().getExternalContext().setRequest(request);
+      Pages.instance().preRender(FacesContext.getCurrentInstance());      
+   }
+   
+   @Test
+   public void testGetCallActionEscaped()
+   {
+      EnhancedMockHttpServletRequest request = new EnhancedMockHttpServletRequest();
+      request.addParameter("actionOutcome", "%3d%23%7dvariable%7b");
+      FacesContext.getCurrentInstance().getExternalContext().setRequest(request);
+      Pages.instance().preRender(FacesContext.getCurrentInstance());      
+   }
+   
    public static class TestValidator implements Validator
    {
       public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException



More information about the seam-commits mailing list