/* * JBoss, Home of Professional Open Source. * Copyright 2007, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.jsfunit.context; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.faces.context.ExternalContext; import javax.faces.context.Flash; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.jboss.jsfunit.framework.Environment; /** * The JSFUnitExternalContext is created at the end of the JSF lifecycle. It * caches as much as possible from the "real" ExternalContext. * * Because the Servlet container is allowed to recycle request and response * objects that the ExternalContext relies upon, a few methods could yield * unexpected results. These methods are noted in the javadoc. * * @author Stan Silvert * @since 1.0 */ public class JSFUnitExternalContext extends ExternalContext { private ExternalContext delegate; private JSFUnitHttpServletRequest httpServletRequest; private Map cookieMap; private String requestContextPath; private String remoteUser; private Map initParameterMap; private ServletContext context; private String authType; private Map applicationMap; private Map requestHeaderMap; private Map requestHeaderValuesMap; private Locale locale; private List locales; private Map requestMap; private Map requestParameterMap; private Map requestParameterValuesMap; private String requestPathInfo; private String requestServletPath; private Object session; private Map sessionMap; private Principal userPrincipal; private int requestContentLength; public JSFUnitExternalContext(ExternalContext delegate) { this.delegate = delegate; // cache most of the data from the "real" ExternalContext this.cookieMap = new HashMap(delegate.getRequestCookieMap()); this.requestContextPath = delegate.getRequestContextPath(); this.remoteUser = delegate.getRemoteUser(); this.initParameterMap = new HashMap(delegate.getInitParameterMap()); this.context = (ServletContext)delegate.getContext(); this.authType = delegate.getAuthType(); this.applicationMap = new NoNewEntryMap(delegate.getApplicationMap()); this.requestHeaderMap = new HashMap(delegate.getRequestHeaderMap()); this.requestHeaderValuesMap = new HashMap(delegate.getRequestHeaderValuesMap()); this.locale = delegate.getRequestLocale(); this.locales = new ArrayList(); for (Iterator i = delegate.getRequestLocales(); i.hasNext();) { this.locales.add(i.next()); } this.requestMap = new NoNewEntryMap(delegate.getRequestMap()); this.requestParameterMap = new HashMap(delegate.getRequestParameterMap()); this.requestParameterValuesMap = new HashMap(delegate.getRequestParameterValuesMap()); this.requestPathInfo = delegate.getRequestPathInfo(); this.requestServletPath = delegate.getRequestServletPath(); this.session = new JSFUnitHttpSession((HttpSession)delegate.getSession(true)); this.sessionMap = new NoNewEntryMap(delegate.getSessionMap()); this.userPrincipal = delegate.getUserPrincipal(); if (Environment.is20Compatible()) { this.requestContentLength = delegate.getRequestContentLength(); } this.httpServletRequest = new JSFUnitHttpServletRequest(this, (HttpServletRequest)delegate.getRequest()); } @Override public Map getRequestCookieMap() { return this.cookieMap; } @Override public String getRequestContextPath() { return this.requestContextPath; } @Override public String getRemoteUser() { return this.remoteUser; } @Override public String getInitParameter(String string) { return (String)this.initParameterMap.get(string); } @Override public Map getInitParameterMap() { return this.initParameterMap; } @Override public Object getContext() { return this.context; } @Override public String getAuthType() { return this.authType; } /** * Warning: The write-through capabilities of this Map are disabled for * JSFUnit tests. You can still modify the Application attributes * through the ServletContext. It is not recommended to do this in * a JSFUnit test. Ideally, JSFUnit tests should only examine the state of * the system, not change it.<br/> * But if you must, here is how to do it:<br/> * <code> * HttpSession session = (HttpSession)externalContext.getSession();<br/> * ServletContext appContext = session.getServletContext();<br/> * appContext.setAttribute("documentsByPath", "bar"); * </code> */ @Override public Map getApplicationMap() { return this.applicationMap; } @Override public Map getRequestHeaderMap() { return this.requestHeaderMap; } @Override public Map getRequestHeaderValuesMap() { return this.requestHeaderValuesMap; } @Override public Locale getRequestLocale() { return this.locale; } @Override public Iterator getRequestLocales() { return this.locales.iterator(); } @Override public Map getRequestMap() { return this.requestMap; } @Override public Map getRequestParameterMap() { return this.requestParameterMap; } @Override public Iterator getRequestParameterNames() { return this.requestParameterMap.keySet().iterator(); } @Override public Map getRequestParameterValuesMap() { return this.requestParameterValuesMap; } @Override public String getRequestPathInfo() { return this.requestPathInfo; } @Override public String getRequestServletPath() { return this.requestServletPath; } @Override public Object getSession(boolean b) { return this.session; } /** * Warning: The write-through capabilities of this Map are disabled for * JSFUnit tests. In other words, modifications to the Map do not actually * affect the HttpSession. You can still modify the Session attributes * using the 'live' HttpSession obtained from the getSession() method. * It is not recommended to do this in a JSFUnit test. Ideally, JSFUnit * tests should only examine the state of the system, not change it.<br/> * But if you must, here is how to do it:<br/> * <code> * HttpSession session = (HttpSession)externalContext.getSession();<br/> * session.setAttribute("documentsByPath", "bar"); * </code> */ @Override public Map getSessionMap() { return this.sessionMap; } @Override public Principal getUserPrincipal() { return this.userPrincipal; } @Override public URL getResource(String string) throws MalformedURLException { return this.context.getResource(string); } @Override public InputStream getResourceAsStream(String string) { return this.context.getResourceAsStream(string); } @Override public Set getResourcePaths(String string) { return this.context.getResourcePaths(string); } @Override public void log(String string, Throwable throwable) { this.context.log(string, throwable); } @Override public void log(String string) { this.context.log(string); } @Override public String encodeNamespace(String string) { return string; } /** * Return the url unchanged. This is OK in JSFUnit because we know that we * are using cookies for the jsessionid. * * @param url The url to encode. * * @return The url unchanged. * * @throws NullPointerException if the url is null */ @Override public String encodeResourceURL(String url) { if (url == null) throw new NullPointerException("url can not be null."); return url; } /** * Return the url unchanged. This is OK in JSFUnit because we know that we * are using cookies for the jsessionid. * * @param url The url to encode. * * @return The url unchanged. * * @throws NullPointerException if the url is null */ @Override public String encodeActionURL(String url) { if (url == null) throw new NullPointerException("url can not be null."); return url; } //----------------- JSF 2.0 Methods -------------------------------------------- /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public void addResponseCookie(String name, String value, Map<String, Object> properties) { delegate.addResponseCookie(name, value, properties); } @Override public String getMimeType(String file) { return context.getMimeType(file); } @Override public String getRealPath(String path) { return context.getRealPath(path); } @Override public String getRequestCharacterEncoding() { return httpServletRequest.getCharacterEncoding(); } @Override public String getRequestContentType() { return httpServletRequest.getContentType(); } @Override public String getRequestScheme() { return httpServletRequest.getScheme(); } @Override public String getRequestServerName() { return httpServletRequest.getServerName(); } @Override public int getRequestServerPort() { return httpServletRequest.getServerPort(); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public String getResponseCharacterEncoding() { return delegate.getResponseCharacterEncoding(); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public String getResponseContentType() { return delegate.getResponseContentType(); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public OutputStream getResponseOutputStream() throws IOException { return delegate.getResponseOutputStream(); } @Override public void invalidateSession() { ((JSFUnitHttpSession)session).invalidate(); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public void setRequest(Object request) { delegate.setRequest(request); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public void setRequestCharacterEncoding(String encoding) throws UnsupportedEncodingException { delegate.setRequestCharacterEncoding(encoding); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public void setResponse(Object response) { delegate.setResponse(response); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public void setResponseCharacterEncoding(String encoding) { delegate.setResponseCharacterEncoding(encoding); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public void setResponseContentType(String contentType) { delegate.setResponseContentType(contentType); } @Override public Flash getFlash() { return delegate.getFlash(); } @Override public void addResponseHeader(String name, String value) { delegate.addResponseHeader(name, value); } @Override public String encodeBookmarkableURL(String baseUrl, Map<String, List<String>> parameters) { return delegate.encodeBookmarkableURL(baseUrl, parameters); } @Override public String encodePartialActionURL(String url) { return delegate.encodePartialActionURL(url); } @Override public String encodeRedirectURL(String baseUrl, Map<String, List<String>> parameters) { return delegate.encodeRedirectURL(baseUrl, parameters); } @Override public String getContextName() { return delegate.getContextName(); } @Override public int getRequestContentLength() { return delegate.getRequestContentLength(); } @Override public int getResponseBufferSize() { return delegate.getResponseBufferSize(); } @Override public Writer getResponseOutputWriter() throws IOException { return delegate.getResponseOutputWriter(); } @Override public boolean isResponseCommitted() { return delegate.isResponseCommitted(); } @Override public void responseFlushBuffer() throws IOException { delegate.responseFlushBuffer(); } @Override public void responseReset() { delegate.responseReset(); } @Override public void responseSendError(int statusCode, String message) throws IOException { delegate.responseSendError(statusCode, message); } @Override public void setResponseBufferSize(int size) { delegate.setResponseBufferSize(size); } @Override public void setResponseContentLength(int length) { delegate.setResponseContentLength(length); } @Override public void setResponseHeader(String name, String value) { delegate.setResponseHeader(name, value); } @Override public void setResponseStatus(int statusCode) { delegate.setResponseStatus(statusCode); } //----------------- End JSF 2.0 Methods -------------------------------------------- // ----- Methods that rely on HttpRequest or HttpResponse: These objects may // ----- have been recycled/reclaimed by the servlet container. /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public boolean isUserInRole(String string) { return delegate.isUserInRole(string); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public Object getResponse() { return delegate.getResponse(); } /** * Warning: Calling this method from a JSFUnit test could yield unexpected results. */ @Override public Object getRequest() { return this.httpServletRequest; } // ------------ Unsupported Operations ---------------------------------------------------------- /** * Unsupported method. Since the JSFUnitExternalContext is not active until * the request is over, it doesn't make sense to do a dispatch by calling * this method in a JSFUnit test. * * @throws UnsupportedOperationException if this method is called during * a JSFUnit test. */ @Override public void dispatch(String string) throws IOException { throw new UnsupportedOperationException("Dispatch not allowed after request is complete"); } /** * Unsupported method. Since the JSFUnitExternalContext is not active until * the request is over, it doesn't make sense to do a dispatch by calling * this method in a JSFUnit test. * * @throws UnsupportedOperationException if this method is called during * a JSFUnit test. */ @Override public void redirect(String string) throws IOException { throw new UnsupportedOperationException("Redirect not allowed after request is complete"); } }