From seam-commits at lists.jboss.org Mon Jul 13 12:08:36 2009 Content-Type: multipart/mixed; boundary="===============6935626995255991705==" MIME-Version: 1.0 From: seam-commits at lists.jboss.org To: seam-commits at lists.jboss.org Subject: [seam-commits] Seam SVN: r11279 - in branches/enterprise/JBPAPP_5_0: src/main/org/jboss/seam/mock and 1 other directory. Date: Mon, 13 Jul 2009 11:50:48 -0400 Message-ID: <200907131550.n6DFom75015746@svn01.web.mwc.hst.phx2.redhat.com> --===============6935626995255991705== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Author: manaRH Date: 2009-07-13 11:50:48 -0400 (Mon, 13 Jul 2009) New Revision: 11279 Added: branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/DelegatingSe= rvletInputStream.java branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/DelegatingSe= rvletOutputStream.java branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/EnhancedMock= HttpServletRequest.java branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/EnhancedMock= HttpServletResponse.java branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/HeaderValueH= older.java branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/MockRequestD= ispatcher.java branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/ResourceRequ= estEnvironment.java Removed: branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/AbstractDBUn= itSeamTest.java Modified: branches/enterprise/JBPAPP_5_0/doc/Seam_Reference_Guide/en-US/Webservice= s.xml Log: back ported JBSEAM-4195 Modified: branches/enterprise/JBPAPP_5_0/doc/Seam_Reference_Guide/en-US/Web= services.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- branches/enterprise/JBPAPP_5_0/doc/Seam_Reference_Guide/en-US/Webservic= es.xml 2009-07-13 12:20:22 UTC (rev 11278) +++ branches/enterprise/JBPAPP_5_0/doc/Seam_Reference_Guide/en-US/Webservic= es.xml 2009-07-13 15:50:48 UTC (rev 11279) @@ -599,40 +599,49 @@ Testing resources and providers = - Seam includes an extended unit testing superclass that helps y= ou in creating unit tests for a RESTful - architecture. Extend the ResourceSeamTest c= lass to emulate HTTP requests/response cycles: + Seam includes a unit testing utility class that helps you crea= te unit tests for a RESTful + architecture. Extend the SeamTest class as = usual and use the + ResourceRequestEnvironment.ResourceRequest = to emulate HTTP requests/response cycles: = - getDefaultHeaders() - { - return new HashMap() - {{ - put("Accept", "text/plain"); - }}; + ResourceRequestEnvironment sharedEnvironment; + + @BeforeClass + public void prepareSharedEnvironment() throws Exception { + sharedEnvironment =3D new ResourceRequestEnvironment(this) { + @Override + public Map getDefaultHeaders() { + return new HashMap() {{ + put("Accept", "text/plain"); + }}; + } + }; } = @Test public void test() throws Exception { - new ResourceRequest(Method.GET, "/my/relative/uri) + //Not shared: new ResourceRequest(new ResourceRequestEnvironment(thi= s), Method.GET, "/my/relative/uri) + + new ResourceRequest(sharedEnvironment, Method.GET, "/my/relative/uri) { - @Override - protected void prepareRequest(MockHttpServletRequest request) + protected void prepareRequest(EnhancedMockHttpServletRequest requ= est) { request.addQueryParameter("foo", "123"); request.addHeader("Accept-Language", "en_US, de"); } = @Override - protected void onResponse(MockHttpServletResponse response) + protected void onResponse(EnhancedMockHttpServletResponse respons= e) { assert response.getStatus() =3D=3D 200; assert response.getContentAsString().equals("foobar"); @@ -640,30 +649,22 @@ = }.run(); } - }]]> = This test only executes local calls, it does not communicate w= ith the SeamResourceServlet through TCP. The mock request is passed through the Seam servl= et and filters and the response is then - available for test assertions. Overriding the getDefa= ultHeaders() method allows you - to set request headers for every test method in the test class. + available for test assertions. Overriding the getDefa= ultHeaders() method in a shared + instance of ResourceRequestEnvironment allo= ws you to set request headers for every + test method in the test class. = Note that a ResourceRequest has to be execu= ted in a @Test method - or in a @BeforeMethod callback. You can and= should not execute it in any other callback, - such as @BeforeClass. (This is an implement= ation limitation we will remove in a future - update.) + or in a @BeforeMethod callback. You can not= execute it in any other callback, + such as @BeforeClass. = - - Also note that the imported mock objects are not the same as t= he mock objects you use in other Seam unit - tests, which are in the package org.jboss.seam.mock. The - org.jboss.seam.resteasy.testfwk variations = mimic real requests and responses much - more closely. - - = Deleted: branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/Abstra= ctDBUnitSeamTest.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Added: branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/Delegati= ngServletInputStream.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/DelegatingS= ervletInputStream.java (rev 0) +++ branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/DelegatingS= ervletInputStream.java 2009-07-13 15:50:48 UTC (rev 11279) @@ -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}. + *

+ *

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 null) + */ + public DelegatingServletInputStream(InputStream sourceStream) + { + this.sourceStream =3D sourceStream; + } + + /** + * Return the underlying source stream (never null). + */ + 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_5_0/src/main/org/jboss/seam/mock/Delegati= ngServletOutputStream.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/DelegatingS= ervletOutputStream.java (rev 0) +++ branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/DelegatingS= ervletOutputStream.java 2009-07-13 15:50:48 UTC (rev 11279) @@ -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}. + *

+ *

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 null) + */ + public DelegatingServletOutputStream(OutputStream targetStream) + { + this.targetStream =3D targetStream; + } + + /** + * Return the underlying target stream (never null). + */ + 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 Copied: branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/Enhance= dMockHttpServletRequest.java (from rev 11257, branches/enterprise/JBPAPP_5_= 0/src/main/org/jboss/seam/mock/MockHttpServletRequest.java) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/EnhancedMoc= kHttpServletRequest.java (rev 0) +++ branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/EnhancedMoc= kHttpServletRequest.java 2009-07-13 15:50:48 UTC (rev 11279) @@ -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. + *

+ *

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 =3D "http"; + + /** + * The default server address: '127.0.0.1'. + */ + public static final String DEFAULT_SERVER_ADDR =3D "127.0.0.1"; + + /** + * The default server name: 'localhost'. + */ + public static final String DEFAULT_SERVER_NAME =3D "localhost"; + + /** + * The default server port: '80'. + */ + public static final int DEFAULT_SERVER_PORT =3D 80; + + /** + * The default remote address: '127.0.0.1'. + */ + public static final String DEFAULT_REMOTE_ADDR =3D "127.0.0.1"; + + /** + * The default remote host: 'localhost'. + */ + public static final String DEFAULT_REMOTE_HOST =3D "localhost"; + + private boolean active =3D true; + + + //--------------------------------------------------------------------- + // ServletRequest properties + //--------------------------------------------------------------------- + + private final Hashtable attributes =3D new Hashtable(); + + private String characterEncoding; + + private byte[] content; + + private String contentType; + + private final Map parameters =3D new LinkedHashMap(16); + + private String protocol =3D DEFAULT_PROTOCOL; + + private String scheme =3D DEFAULT_PROTOCOL; + + private String serverName =3D DEFAULT_SERVER_NAME; + + private int serverPort =3D DEFAULT_SERVER_PORT; + + private String remoteAddr =3D DEFAULT_REMOTE_ADDR; + + private String remoteHost =3D DEFAULT_REMOTE_HOST; + + /** + * List of locales in descending order + */ + private final Vector locales =3D new Vector(); + + private boolean secure =3D false; + + private final ServletContext servletContext; + + private int remotePort =3D DEFAULT_SERVER_PORT; + + private String localName =3D DEFAULT_SERVER_NAME; + + private String localAddr =3D DEFAULT_SERVER_ADDR; + + private int localPort =3D DEFAULT_SERVER_PORT; + + + //--------------------------------------------------------------------- + // HttpServletRequest properties + //--------------------------------------------------------------------- + + private String authType; + + private Cookie[] cookies; + + /** + * The key is the lowercase header name; the value is a {@link org.jbos= s.seam.mock.HeaderValueHolder} object. + */ + private final Hashtable headers =3D new Hashtable(); + + private String method; + + private String pathInfo; + + private String contextPath =3D ""; + + private String queryString; + + private Map queryParameters =3D new HashMap(); + + private String remoteUser; + + private Set userRoles =3D new HashSet(); + + private Principal userPrincipal; + + private String requestURI; + + private String servletPath =3D ""; + + private HttpSession session; + + private boolean requestedSessionIdValid =3D true; + + private boolean requestedSessionIdFromCookie =3D true; + + private boolean requestedSessionIdFromURL =3D 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 null) + * @param requestURI the request URI (may be null) + * @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 null to use a default Moc= kServletContext) + * @see MockServletContext + */ + public EnhancedMockHttpServletRequest(ServletContext servletContext) + { + this(servletContext, "", ""); + } + + /** + * Create a new MockHttpServletRequest. + * + * @param servletContext the ServletContext that the request runs in + * (may be null to use a default Moc= kServletContext) + * @param method the request method (may be null) + * @param requestURI the request URI (may be null) + * @see #setMethod + * @see #setRequestURI + * @see MockServletContext + */ + public EnhancedMockHttpServletRequest(ServletContext servletContext, St= ring method, String requestURI) + { + this.servletContext =3D (servletContext !=3D null ? servletContext := new MockServletContext()); + this.method =3D method; + this.requestURI =3D 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()); + } + + public EnhancedMockHttpServletRequest(HttpSession session, String princ= ipalName, Set principalRoles) + { + this(session, principalName, principalRoles, new Cookie[]{}, null); + } + + public EnhancedMockHttpServletRequest(HttpSession session, final String= principalName, Set principalRoles, Cookie[] cookies, String method) + { + this(null, method, ""); + this.session =3D session; + + this.userPrincipal =3D principalName =3D=3D null + ? null + : new Principal() + { + public String getName() + { + return principalName; + } + }; + + this.userRoles =3D principalRoles; + this.cookies =3D 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 =3D false; + } + + /** + * Invalidate this request, clearing its state. + */ + public void invalidate() + { + close(); + clearAttributes(); + } + + /** + * Check whether this request is still active (that is, not completed y= et), + * 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 =3D characterEncoding; + } + + public void setContent(byte[] content) + { + this.content =3D content; + } + + public int getContentLength() + { + return (this.content !=3D null ? this.content.length : -1); + } + + public void setContentType(String contentType) + { + this.contentType =3D contentType; + } + + public String getContentType() + { + return this.contentType; + } + + public ServletInputStream getInputStream() throws IOException + { + if (this.content !=3D null) + { + return new DelegatingServletInputStream(new ByteArrayInputStream(= this.content)); + } + else + { + return null; + } + } + + /** + * Set a single value for the specified HTTP parameter. + *

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. + *

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 replacing 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 =3D params.keySet().iterator(); it.hasNext();) + { + Object key =3D it.next(); + Object value =3D 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 b= e single value " + + " or array of type [" + String.class.getName() + "]"); + } + } + } + + /** + * Add a single value for the specified HTTP parameter. + *

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. + *

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 lis= t. + */ + public void addParameter(String name, String[] values) + { + String[] oldArr =3D (String[]) this.parameters.get(name); + if (oldArr !=3D null) + { + String[] newArr =3D 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 without replacing + * any existing values. To replace existing values, use + * {@link #setParameters(java.util.Map)}. + */ + public void addParameters(Map params) + { + for (Iterator it =3D params.keySet().iterator(); it.hasNext();) + { + Object key =3D it.next(); + Object value =3D 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 b= e single value " + + " or array of type [" + String.class.getName() + "]"); + } + } + } + + /** + * Remove already registered values for the specified HTTP parameter, i= f 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 =3D (String[]) this.parameters.get(name); + return (arr !=3D 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 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 getQueryParameters() + { + return queryParameters; + } + + public void setProtocol(String protocol) + { + this.protocol =3D protocol; + } + + public String getProtocol() + { + return this.protocol; + } + + public void setScheme(String scheme) + { + this.scheme =3D scheme; + } + + public String getScheme() + { + return this.scheme; + } + + public void setServerName(String serverName) + { + this.serverName =3D serverName; + } + + public String getServerName() + { + return this.serverName; + } + + public void setServerPort(int serverPort) + { + this.serverPort =3D serverPort; + } + + public int getServerPort() + { + return this.serverPort; + } + + public BufferedReader getReader() throws UnsupportedEncodingException + { + if (this.content !=3D null) + { + InputStream sourceStream =3D new ByteArrayInputStream(this.conten= t); + Reader sourceReader =3D (this.characterEncoding !=3D null) ? + new InputStreamReader(sourceStream, this.characterEncoding)= : new InputStreamReader(sourceStream); + return new BufferedReader(sourceReader); + } + else + { + return null; + } + } + + public void setRemoteAddr(String remoteAddr) + { + this.remoteAddr =3D remoteAddr; + } + + public String getRemoteAddr() + { + return this.remoteAddr; + } + + public void setRemoteHost(String remoteHost) + { + this.remoteHost =3D remoteHost; + } + + public String getRemoteHost() + { + return this.remoteHost; + } + + public void setAttribute(String name, Object value) + { + checkActive(); + if (value !=3D 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 =3D 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 =3D remotePort; + } + + public int getRemotePort() + { + return this.remotePort; + } + + public void setLocalName(String localName) + { + this.localName =3D localName; + } + + public String getLocalName() + { + return this.localName; + } + + public void setLocalAddr(String localAddr) + { + this.localAddr =3D localAddr; + } + + public String getLocalAddr() + { + return this.localAddr; + } + + public void setLocalPort(int localPort) + { + this.localPort =3D localPort; + } + + public int getLocalPort() + { + return this.localPort; + } + + + //--------------------------------------------------------------------- + // HttpServletRequest interface + //--------------------------------------------------------------------- + + public void setAuthType(String authType) + { + this.authType =3D authType; + } + + public String getAuthType() + { + return this.authType; + } + + public void setCookies(Cookie[] cookies) + { + this.cookies =3D cookies; + } + + public Cookie[] getCookies() + { + return this.cookies; + } + + public void addCookie(Cookie cookie) + { + this.cookies =3D new Cookie[this.cookies.length + 1]; + this.cookies[this.cookies.length - 1] =3D cookie; + } + + /** + * Add a header entry for the given name. + *

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. + *

Multiple values can only be stored as list of Strings, + * following the Servlet spec (see getHeaders accessor). + * As alternative to repeated addHeader 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 =3D HeaderValueHolder.getByName(this.header= s, name); + if (header =3D=3D null) + { + header =3D 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 =3D HeaderValueHolder.getByName(this.header= s, name); + Object value =3D (header !=3D null ? header.getValue() : null); + if (value instanceof Date) + { + return ((Date) value).getTime(); + } + else if (value instanceof Number) + { + return ((Number) value).longValue(); + } + else if (value !=3D null) + { + throw new IllegalArgumentException( + "Value for header '" + name + "' is neither a Date nor a Nu= mber: " + value); + } + else + { + return -1L; + } + } + + public String getHeader(String name) + { + HeaderValueHolder header =3D HeaderValueHolder.getByName(this.header= s, name); + return (header !=3D null ? header.getValue().toString() : null); + } + + public Map getHeaders() + { + Map headerValues =3D new HashMap(); + + for (Object o : this.headers.entrySet()) + { + Map.Entry entry =3D (Map.Entry)o; + String[] values =3D (String[])entry.getValue().getValues().toArra= y(new String[entry.getValue().getValues().size()]); + headerValues.put(entry.getKey(), values); + } + + return headerValues; + } + + public Enumeration getHeaders(String name) + { + HeaderValueHolder header =3D HeaderValueHolder.getByName(this.header= s, name); + return Collections.enumeration(header !=3D null ? header.getValues()= : Collections.EMPTY_LIST); + } + + public Enumeration getHeaderNames() + { + return this.headers.keys(); + } + + public int getIntHeader(String name) + { + HeaderValueHolder header =3D HeaderValueHolder.getByName(this.header= s, name); + Object value =3D (header !=3D 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 !=3D null) + { + throw new NumberFormatException("Value for header '" + name + "' = is not a Number: " + value); + } + else + { + return -1; + } + } + + public void setMethod(String method) + { + this.method =3D method; + } + + public String getMethod() + { + return this.method; + } + + public void setPathInfo(String pathInfo) + { + this.pathInfo =3D pathInfo; + } + + public String getPathInfo() + { + return this.pathInfo; + } + + public String getPathTranslated() + { + return (this.pathInfo !=3D null ? getRealPath(this.pathInfo) : null); + } + + public void setContextPath(String contextPath) + { + this.contextPath =3D contextPath; + } + + public String getContextPath() + { + return this.contextPath !=3D null ? this.contextPath : "/project"; /= / Old mock default + } + + public void setQueryString(String queryString) + { + this.queryString =3D queryString; + } + + public String getQueryString() + { + if (getQueryParameters().size() > 0) + { + StringBuilder q =3D new StringBuilder(queryString); + if (!queryString.endsWith("&")) q.append("&"); + for (Map.Entry entry : getQueryParameters().entry= Set()) + { + q.append(entry.getKey()); + q.append("=3D"); + 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 =3D 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 =3D userPrincipal; + } + + public Principal getUserPrincipal() + { + return this.userPrincipal; + } + + public String getRequestedSessionId() + { + HttpSession session =3D getSession(); + return (session !=3D null ? session.getId() : null); + } + + public void setRequestURI(String requestURI) + { + this.requestURI =3D requestURI; + } + + public String getRequestURI() + { + return this.requestURI; + } + + public StringBuffer getRequestURL() + { + StringBuffer url =3D new StringBuffer(this.scheme); + url.append("://").append(this.serverName).append(':').append(this.se= rverPort); + url.append(getRequestURI()); + return url; + } + + public void setServletPath(String servletPath) + { + this.servletPath =3D 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 =3D ((MockHttpSession) session); + ... + } + */ + this.session =3D session; + } + + public HttpSession getSession(boolean create) + { + checkActive(); + // Reset session if invalidated. + if (this.session instanceof MockHttpSession && ((MockHttpSession) th= is.session).isInvalid()) + { + this.session =3D null; + } + // Create new session if necessary. + if (this.session =3D=3D null && create) + { + this.session =3D new MockHttpSession(this.servletContext); + } + return this.session; + } + + public HttpSession getSession() + { + return getSession(true); + } + + public void setRequestedSessionIdValid(boolean requestedSessionIdValid) + { + this.requestedSessionIdValid =3D requestedSessionIdValid; + } + + public boolean isRequestedSessionIdValid() + { + return this.requestedSessionIdValid; + } + + public void setRequestedSessionIdFromCookie(boolean requestedSessionIdF= romCookie) + { + this.requestedSessionIdFromCookie =3D requestedSessionIdFromCookie; + } + + public boolean isRequestedSessionIdFromCookie() + { + return this.requestedSessionIdFromCookie; + } + + public void setRequestedSessionIdFromURL(boolean requestedSessionIdFrom= URL) + { + this.requestedSessionIdFromURL =3D requestedSessionIdFromURL; + } + + public boolean isRequestedSessionIdFromURL() + { + return this.requestedSessionIdFromURL; + } + + public boolean isRequestedSessionIdFromUrl() + { + return isRequestedSessionIdFromURL(); + } + + public boolean isAllParametersInQueryString() { + return true; + } + +} \ No newline at end of file Copied: branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/Enhance= dMockHttpServletResponse.java (from rev 11257, branches/enterprise/JBPAPP_5= _0/src/main/org/jboss/seam/mock/MockHttpServletResponse.java) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/EnhancedMoc= kHttpServletResponse.java (rev 0) +++ branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/EnhancedMoc= kHttpServletResponse.java 2009-07-13 15:50:48 UTC (rev 11279) @@ -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.HttpServletRespons= e} + * interface. Supports the Servlet 2.4 API level. + * + *

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 HttpServletRespons= e { + + public static final int DEFAULT_SERVER_PORT =3D 80; + + private static final String CHARSET_PREFIX =3D "charset=3D"; + + + //--------------------------------------------------------------------- + // ServletResponse properties + //--------------------------------------------------------------------- + + private boolean outputStreamAccessAllowed =3D true; + + private boolean writerAccessAllowed =3D true; + + private String characterEncoding =3D "ISO-8859-1"; + + private final ByteArrayOutputStream content =3D new ByteArrayOutputStream= (); + + private final ServletOutputStream outputStream =3D new ResponseServletOut= putStream(this.content); + + private PrintWriter writer; + + private int contentLength =3D 0; + + private String contentType; + + private int bufferSize =3D 4096; + + private boolean committed; + + private Locale locale =3D Locale.getDefault(); + + + //--------------------------------------------------------------------- + // HttpServletResponse properties + //--------------------------------------------------------------------- + + private final List cookies =3D new ArrayList(); + + /** + * The key is the lowercase header name; the value is a {@link org.jboss.= seam.mock.HeaderValueHolder} object. + */ + private final Map headers =3D new HashMap(); + + private int status =3D HttpServletResponse.SC_OK; + + private String statusMessage; + + private String redirectedUrl; + + private String forwardedUrl; + + private String includedUrl; + + + //--------------------------------------------------------------------- + // ServletResponse interface + //--------------------------------------------------------------------- + + /** + * Set whether {@link #getOutputStream()} access is allowed. + *

Default is true. + */ + public void setOutputStreamAccessAllowed(boolean outputStreamAccessAllowe= d) { + this.outputStreamAccessAllowed =3D outputStreamAccessAllowed; + } + + /** + * Return whether {@link #getOutputStream()} access is allowed. + */ + public boolean isOutputStreamAccessAllowed() { + return this.outputStreamAccessAllowed; + } + + /** + * Set whether {@link #getWriter()} access is allowed. + *

Default is true. + */ + public void setWriterAccessAllowed(boolean writerAccessAllowed) { + this.writerAccessAllowed =3D writerAccessAllowed; + } + + /** + * Return whether {@link #getOutputStream()} access is allowed. + */ + public boolean isWriterAccessAllowed() { + return this.writerAccessAllowed; + } + + public void setCharacterEncoding(String characterEncoding) { + this.characterEncoding =3D 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 =3D=3D null) { + Writer targetWriter =3D (this.characterEncoding !=3D null ? + new OutputStreamWriter(this.content, this.characterEncoding) : new Ou= tputStreamWriter(this.content)); + this.writer =3D new ResponsePrintWriter(targetWriter); + } + return this.writer; + } + + public byte[] getContentAsByteArray() { + flushBuffer(); + return this.content.toByteArray(); + } + + public String getContentAsString() { + flushBuffer(); + try { + return (this.characterEncoding !=3D null) ? + this.content.toString(this.characterEncoding) : this.conten= t.toString(); + } catch (UnsupportedEncodingException ex) { + throw new RuntimeException(ex); + } + } + + public void setContentLength(int contentLength) { + this.contentLength =3D contentLength; + } + + public int getContentLength() { + return this.contentLength; + } + + public void setContentType(String contentType) { + this.contentType =3D contentType; + if (contentType !=3D null) { + int charsetIndex =3D contentType.toLowerCase().indexOf(CHARSET_PREFIX); + if (charsetIndex !=3D -1) { + String encoding =3D contentType.substring(charsetIndex + CHARSET_PREFI= X.length()); + setCharacterEncoding(encoding); + } + } + } + + public String getContentType() { + return this.contentType; + } + + public void setBufferSize(int bufferSize) { + this.bufferSize =3D 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 alre= ady committed"); + } + this.content.reset(); + } + + private void setCommittedIfBufferSizeExceeded() { + int bufSize =3D getBufferSize(); + if (bufSize > 0 && this.content.size() > bufSize) { + setCommitted(true); + } + } + + public void setCommitted(boolean committed) { + this.committed =3D committed; + } + + public boolean isCommitted() { + return this.committed; + } + + public void reset() { + resetBuffer(); + this.characterEncoding =3D null; + this.contentLength =3D 0; + this.contentType =3D null; + this.locale =3D null; + this.cookies.clear(); + this.headers.clear(); + this.status =3D HttpServletResponse.SC_OK; + this.statusMessage =3D null; + } + + public void setLocale(Locale locale) { + this.locale =3D 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 =3D this.cookies.iterator(); it.hasNext();) { + Cookie cookie =3D (Cookie) it.next(); + if (name.equals(cookie.getName())) { + return cookie; + } + } + return null; + } + + public boolean containsHeader(String name) { + return (HeaderValueHolder.getByName(this.headers, name) !=3D null); + } + + /** + * Return the names of all specified headers as a Set of Strings. + * @return the Set of header name Strings, or a= n empty Set if none + */ + public Set getHeaderNames() { + return this.headers.keySet(); + } + + /** + * Return the primary value for the given header, if any. + *

Will return the first value in case of multiple values. + * @param name the name of the header + * @return the associated header value, or null if none + */ + public Object getHeader(String name) { + HeaderValueHolder header =3D HeaderValueHolder.getByName(this.headers, n= ame); + return (header !=3D 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 =3D HeaderValueHolder.getByName(this.headers, n= ame); + return (header !=3D null ? header.getValues() : Collections.EMPTY_LIST); + } + + /** + * The default implementation returns the given URL String as-is. + *

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. + *

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 =3D status; + this.statusMessage =3D 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 =3D status; + setCommitted(true); + } + + public void sendRedirect(String url) throws IOException { + if (isCommitted()) { + throw new IllegalStateException("Cannot send redirect - response is alr= eady committed"); + } + this.redirectedUrl =3D 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 =3D HeaderValueHolder.getByName(this.headers, n= ame); + if (header =3D=3D null) { + header =3D new HeaderValueHolder(); + this.headers.put(name, header); + } + if (replace) { + header.setValue(value); + } + else { + header.addValue(value); + } + } + + public void setStatus(int status) { + this.status =3D status; + } + + public void setStatus(int status, String statusMessage) { + this.status =3D status; + this.statusMessage =3D statusMessage; + } + + public int getStatus() { + return this.status; + } + + public String getStatusMessage() { + return this.statusMessage; + } + + + //--------------------------------------------------------------------- + // Methods for MockRequestDispatcher + //--------------------------------------------------------------------- + + public void setForwardedUrl(String forwardedUrl) { + this.forwardedUrl =3D forwardedUrl; + } + + public String getForwardedUrl() { + return this.forwardedUrl; + } + + public void setIncludedUrl(String includedUrl) { + this.includedUrl =3D 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 DelegatingServletOutput= Stream + { + + 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_5_0/src/main/org/jboss/seam/mock/HeaderVa= lueHolder.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/HeaderValue= Holder.java (rev 0) +++ branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/HeaderValue= Holder.java 2009-07-13 15:50:48 UTC (rev 11279) @@ -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 =3D 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 =3D 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 null if none found + */ + public static HeaderValueHolder getByName(Map headers, String name) + { + for (Iterator it =3D headers.keySet().iterator(); it.hasNext();) + { + String headerName =3D (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 =3D=3D null) + { + return new Object[0]; + } + if (!source.getClass().isArray()) + { + throw new IllegalArgumentException("Source is not an array: " + s= ource); + } + int length =3D Array.getLength(source); + if (length =3D=3D 0) + { + return new Object[0]; + } + Class wrapperType =3D Array.get(source, 0).getClass(); + Object[] newArray =3D (Object[]) Array.newInstance(wrapperType, leng= th); + for (int i =3D 0; i < length; i++) + { + newArray[i] =3D Array.get(source, i); + } + return newArray; + } + +} \ No newline at end of file Added: branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/MockRequ= estDispatcher.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/MockRequest= Dispatcher.java (rev 0) +++ branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/MockRequest= Dispatcher.java 2009-07-13 15:50:48 UTC (rev 11279) @@ -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} inte= rface. + *

+ *

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 =3D 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 =3D url; + } + + + public void forward(ServletRequest request, ServletResponse response) + { + if (response.isCommitted()) + { + throw new IllegalStateException("Cannot perform forward - respons= e 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} dec= orators if necessary. + */ + protected EnhancedMockHttpServletResponse getMockHttpServletResponse(Se= rvletResponse response) + { + if (response instanceof EnhancedMockHttpServletResponse) + { + return (EnhancedMockHttpServletResponse) response; + } + if (response instanceof HttpServletResponseWrapper) + { + return getMockHttpServletResponse(((HttpServletResponseWrapper) r= esponse).getResponse()); + } + throw new IllegalArgumentException("MockRequestDispatcher requires M= ockHttpServletResponse"); + } + +} \ No newline at end of file Added: branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/Resource= RequestEnvironment.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/ResourceReq= uestEnvironment.java (rev 0) +++ branches/enterprise/JBPAPP_5_0/src/main/org/jboss/seam/mock/ResourceReq= uestEnvironment.java 2009-07-13 15:50:48 UTC (rev 11279) @@ -0,0 +1,267 @@ +package org.jboss.seam.mock; + +import org.jboss.seam.servlet.SeamResourceServlet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.Cookie; +import javax.servlet.ServletException; +import javax.servlet.ServletResponse; +import javax.servlet.ServletRequest; +import javax.servlet.FilterChain; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import java.util.Collections; +import java.util.Set; +import java.util.List; +import java.util.Map; +import java.util.Enumeration; +import java.security.Principal; +import java.io.IOException; + +/** + * Executes (through local calls, not TCP sockets) an HTTP request in a un= it test, passing it through + * the Seam resource handlers and filters. + * + *

+ * This class is supposed to be used within a SeamTest, in= fact, you need + * to pass an instance of SeamTest into its constructor. This pre= pares the environment + * for the resource request processing. You can either share an instance o= f the environment between + * all your test methods (prepare it in @BeforeClass) or you= can create a new instance + * for each ResourceRequest: + *

+ * + *
+ * import org.jboss.seam.mock.ResourceRequestEnvironment;
+ * import org.jboss.seam.mock.EnhancedMockHttpServletRequest;
+ * import org.jboss.seam.mock.EnhancedMockHttpServletResponse;
+ * import static org.jboss.seam.mock.ResourceRequestEnvironment.ResourceRe=
quest;
+ * import static org.jboss.seam.mock.ResourceRequestEnvironment.Method;
+ *
+ * public class MyTest extends SeamTest {
+ *
+ *    ResourceRequestEnvironment sharedEnvironment;
+ *
+ *    @BeforeClass
+ *    public void prepareSharedEnvironment() throws Exception {
+ *        sharedEnvironment =3D new ResourceRequestEnvironment(this) {
+ *             @Override
+ *             public Map getDefaultHeaders() {
+ *                return new HashMap() {{
+ *                    put("Accept", "text/plain");
+ *                }};
+ *             }
+ *          };
+ *    }
+ *
+ *    @Test
+ *    public void test() throws Exception
+ *    {
+ *       //Not shared: new ResourceRequest(new ResourceRequestEnvironment(=
this), Method.GET, "/my/relative/uri)
+ *
+ *       new ResourceRequest(sharedEnvironment, Method.GET, "/my/relative/=
uri)
+ *       {
+ *
+ *          @Override
+ *          protected void prepareRequest(EnhancedMockHttpServletRequest r=
equest)
+ *          {
+ *             request.addQueryParameter("foo", "123");
+ *             request.addHeader("Accept-Language", "en_US, de");
+ *          }
+ *
+ *          @Override
+ *          protected void onResponse(EnhancedMockHttpServletResponse resp=
onse)
+ *          {
+ *             assert response.getStatus() =3D=3D 200;
+ *             assert response.getContentAsString().equals("foobar");
+ *          }
+ *
+ *       }.run();
+ *    }
+ *
+ * }
+ * 
+ *

+ * Note that in a SeamTest the (mock) HTTP session is always shar= ed between all requests in a particular test + * method. Each test method however executes with a new (mock) HTTP sessio= n. Design your tests accordingly, this is not + * configurable. + *

+ *

+ * IMPORTANT: A ResourceRequest has to be executed in a @T= est method or in a + * @BeforeMethod callback. You can not execute it in any other ca= llback, such * as @BeforeClass. + *

+ * + * @author Christian Bauer + */ +public class ResourceRequestEnvironment +{ + + public enum Method + { + GET, PUT, POST, DELETE, HEAD, OPTIONS + } + + final protected AbstractSeamTest seamTest; + final protected SeamResourceServlet resourceServlet; + + public ResourceRequestEnvironment(AbstractSeamTest seamTest) + { + this.seamTest =3D seamTest; + resourceServlet =3D new SeamResourceServlet(); + try { + resourceServlet.init( + new ServletConfig() + { + public String getServletName() + { + return "Seam Resource Servlet"; + } + + public ServletContext getServletContext() + { + return ResourceRequestEnvironment.this.seamTest.servl= etContext; + } + + public String getInitParameter(String s) + { + return null; + } + + public Enumeration getInitParameterNames() + { + return null; + } + } + ); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + public static class ResourceRequest + { + + final private ResourceRequestEnvironment environment; + private Method httpMethod; + private String requestPath; + private EnhancedMockHttpServletRequest request; + private EnhancedMockHttpServletResponse response; + + public ResourceRequest(ResourceRequestEnvironment environment, Metho= d httpMethod, String requestPath) + { + this.environment =3D environment; + this.httpMethod =3D httpMethod; + this.requestPath =3D environment.getServletPath() + (requestPath.= startsWith("/") ? requestPath : "/" + requestPath); + } + + public void run() throws Exception + { + init(); + prepareRequest(request); + environment.seamTest.seamFilter.doFilter(request, response, new F= ilterChain() + { + public void doFilter(ServletRequest request, ServletResponse r= esponse) throws IOException, ServletException + { + environment.resourceServlet.service(request, response); + } + }); + environment.seamTest.seamFilter.destroy(); + onResponse(getResponse()); + } + + protected void init() + { + request =3D createRequest(); + response =3D createResponse(); + + request.setMethod(httpMethod.toString()); + request.setRequestURI(requestPath); + + request.setServletPath(environment.getServletPath()); + + request.setCookies(getCookies().toArray(new Cookie[getCookies().s= ize()])); + + for (Map.Entry entry : environment.getDefaultHead= ers().entrySet()) + { + request.addHeader(entry.getKey(), entry.getValue()); + } + + request.setUserPrincipal( + new Principal() + { + public String getName() + { + return getPrincipalName(); + } + } + ); + for (String role : getPrincipalRoles()) + { + request.addUserRole(role); + } + + // Use the (mock) HttpSession that Seam uses, see AbstractSeamTest + request.setSession(environment.seamTest.session); + + } + + protected EnhancedMockHttpServletRequest createRequest() + { + return new EnhancedMockHttpServletRequest(); + } + + protected EnhancedMockHttpServletResponse createResponse() + { + return new EnhancedMockHttpServletResponse(); + } + + protected Map getRequestQueryParameters() + { + return Collections.EMPTY_MAP; + } + + protected List getCookies() + { + return Collections.EMPTY_LIST; + } + + protected String getPrincipalName() + { + return null; + } + + protected Set getPrincipalRoles() + { + return Collections.EMPTY_SET; + } + + protected void prepareRequest(EnhancedMockHttpServletRequest request) + { + } + + protected void onResponse(EnhancedMockHttpServletResponse response) + { + } + + public HttpServletRequest getRequest() + { + return request; + } + + public EnhancedMockHttpServletResponse getResponse() + { + return response; + } + + } + + public String getServletPath() + { + return "/seam/resource"; + } + + public Map getDefaultHeaders() + { + return Collections.EMPTY_MAP; + } + +} --===============6935626995255991705==--