001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.mock.web; 018 019import java.io.IOException; 020import java.io.UnsupportedEncodingException; 021import java.util.Collections; 022import java.util.Enumeration; 023import java.util.LinkedHashMap; 024import java.util.LinkedHashSet; 025import java.util.Map; 026import javax.el.ELContext; 027import javax.servlet.Servlet; 028import javax.servlet.ServletConfig; 029import javax.servlet.ServletContext; 030import javax.servlet.ServletException; 031import javax.servlet.ServletRequest; 032import javax.servlet.ServletResponse; 033import javax.servlet.http.HttpServletRequest; 034import javax.servlet.http.HttpServletResponse; 035import javax.servlet.http.HttpSession; 036import javax.servlet.jsp.JspWriter; 037import javax.servlet.jsp.PageContext; 038 039import org.springframework.util.Assert; 040 041/** 042 * Mock implementation of the {@link javax.servlet.jsp.PageContext} interface. 043 * Only necessary for testing applications when testing custom JSP tags. 044 * 045 * <p>Note: Expects initialization via the constructor rather than via the 046 * {@code PageContext.initialize} method. Does not support writing to a 047 * JspWriter, request dispatching, or {@code handlePageException} calls. 048 * 049 * @author Juergen Hoeller 050 * @since 1.0.2 051 */ 052public class MockPageContext extends PageContext { 053 054 private final ServletContext servletContext; 055 056 private final HttpServletRequest request; 057 058 private final HttpServletResponse response; 059 060 private final ServletConfig servletConfig; 061 062 private final Map<String, Object> attributes = new LinkedHashMap<String, Object>(); 063 064 private JspWriter out; 065 066 067 /** 068 * Create new MockPageContext with a default {@link MockServletContext}, 069 * {@link MockHttpServletRequest}, {@link MockHttpServletResponse}, 070 * {@link MockServletConfig}. 071 */ 072 public MockPageContext() { 073 this(null, null, null, null); 074 } 075 076 /** 077 * Create new MockPageContext with a default {@link MockHttpServletRequest}, 078 * {@link MockHttpServletResponse}, {@link MockServletConfig}. 079 * @param servletContext the ServletContext that the JSP page runs in 080 * (only necessary when actually accessing the ServletContext) 081 */ 082 public MockPageContext(ServletContext servletContext) { 083 this(servletContext, null, null, null); 084 } 085 086 /** 087 * Create new MockPageContext with a MockHttpServletResponse, 088 * MockServletConfig. 089 * @param servletContext the ServletContext that the JSP page runs in 090 * @param request the current HttpServletRequest 091 * (only necessary when actually accessing the request) 092 */ 093 public MockPageContext(ServletContext servletContext, HttpServletRequest request) { 094 this(servletContext, request, null, null); 095 } 096 097 /** 098 * Create new MockPageContext with a MockServletConfig. 099 * @param servletContext the ServletContext that the JSP page runs in 100 * @param request the current HttpServletRequest 101 * @param response the current HttpServletResponse 102 * (only necessary when actually writing to the response) 103 */ 104 public MockPageContext(ServletContext servletContext, HttpServletRequest request, HttpServletResponse response) { 105 this(servletContext, request, response, null); 106 } 107 108 /** 109 * Create new MockServletConfig. 110 * @param servletContext the ServletContext that the JSP page runs in 111 * @param request the current HttpServletRequest 112 * @param response the current HttpServletResponse 113 * @param servletConfig the ServletConfig (hardly ever accessed from within a tag) 114 */ 115 public MockPageContext(ServletContext servletContext, HttpServletRequest request, 116 HttpServletResponse response, ServletConfig servletConfig) { 117 118 this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); 119 this.request = (request != null ? request : new MockHttpServletRequest(servletContext)); 120 this.response = (response != null ? response : new MockHttpServletResponse()); 121 this.servletConfig = (servletConfig != null ? servletConfig : new MockServletConfig(servletContext)); 122 } 123 124 125 @Override 126 public void initialize( 127 Servlet servlet, ServletRequest request, ServletResponse response, 128 String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush) { 129 130 throw new UnsupportedOperationException("Use appropriate constructor"); 131 } 132 133 @Override 134 public void release() { 135 } 136 137 @Override 138 public void setAttribute(String name, Object value) { 139 Assert.notNull(name, "Attribute name must not be null"); 140 if (value != null) { 141 this.attributes.put(name, value); 142 } 143 else { 144 this.attributes.remove(name); 145 } 146 } 147 148 @Override 149 public void setAttribute(String name, Object value, int scope) { 150 Assert.notNull(name, "Attribute name must not be null"); 151 switch (scope) { 152 case PAGE_SCOPE: 153 setAttribute(name, value); 154 break; 155 case REQUEST_SCOPE: 156 this.request.setAttribute(name, value); 157 break; 158 case SESSION_SCOPE: 159 this.request.getSession().setAttribute(name, value); 160 break; 161 case APPLICATION_SCOPE: 162 this.servletContext.setAttribute(name, value); 163 break; 164 default: 165 throw new IllegalArgumentException("Invalid scope: " + scope); 166 } 167 } 168 169 @Override 170 public Object getAttribute(String name) { 171 Assert.notNull(name, "Attribute name must not be null"); 172 return this.attributes.get(name); 173 } 174 175 @Override 176 public Object getAttribute(String name, int scope) { 177 Assert.notNull(name, "Attribute name must not be null"); 178 switch (scope) { 179 case PAGE_SCOPE: 180 return getAttribute(name); 181 case REQUEST_SCOPE: 182 return this.request.getAttribute(name); 183 case SESSION_SCOPE: 184 HttpSession session = this.request.getSession(false); 185 return (session != null ? session.getAttribute(name) : null); 186 case APPLICATION_SCOPE: 187 return this.servletContext.getAttribute(name); 188 default: 189 throw new IllegalArgumentException("Invalid scope: " + scope); 190 } 191 } 192 193 @Override 194 public Object findAttribute(String name) { 195 Object value = getAttribute(name); 196 if (value == null) { 197 value = getAttribute(name, REQUEST_SCOPE); 198 if (value == null) { 199 value = getAttribute(name, SESSION_SCOPE); 200 if (value == null) { 201 value = getAttribute(name, APPLICATION_SCOPE); 202 } 203 } 204 } 205 return value; 206 } 207 208 @Override 209 public void removeAttribute(String name) { 210 Assert.notNull(name, "Attribute name must not be null"); 211 this.removeAttribute(name, PageContext.PAGE_SCOPE); 212 this.removeAttribute(name, PageContext.REQUEST_SCOPE); 213 this.removeAttribute(name, PageContext.SESSION_SCOPE); 214 this.removeAttribute(name, PageContext.APPLICATION_SCOPE); 215 } 216 217 @Override 218 public void removeAttribute(String name, int scope) { 219 Assert.notNull(name, "Attribute name must not be null"); 220 switch (scope) { 221 case PAGE_SCOPE: 222 this.attributes.remove(name); 223 break; 224 case REQUEST_SCOPE: 225 this.request.removeAttribute(name); 226 break; 227 case SESSION_SCOPE: 228 this.request.getSession().removeAttribute(name); 229 break; 230 case APPLICATION_SCOPE: 231 this.servletContext.removeAttribute(name); 232 break; 233 default: 234 throw new IllegalArgumentException("Invalid scope: " + scope); 235 } 236 } 237 238 @Override 239 public int getAttributesScope(String name) { 240 if (getAttribute(name) != null) { 241 return PAGE_SCOPE; 242 } 243 else if (getAttribute(name, REQUEST_SCOPE) != null) { 244 return REQUEST_SCOPE; 245 } 246 else if (getAttribute(name, SESSION_SCOPE) != null) { 247 return SESSION_SCOPE; 248 } 249 else if (getAttribute(name, APPLICATION_SCOPE) != null) { 250 return APPLICATION_SCOPE; 251 } 252 else { 253 return 0; 254 } 255 } 256 257 public Enumeration<String> getAttributeNames() { 258 return Collections.enumeration(new LinkedHashSet<String>(this.attributes.keySet())); 259 } 260 261 @Override 262 public Enumeration<String> getAttributeNamesInScope(int scope) { 263 switch (scope) { 264 case PAGE_SCOPE: 265 return getAttributeNames(); 266 case REQUEST_SCOPE: 267 return this.request.getAttributeNames(); 268 case SESSION_SCOPE: 269 HttpSession session = this.request.getSession(false); 270 return (session != null ? session.getAttributeNames() : null); 271 case APPLICATION_SCOPE: 272 return this.servletContext.getAttributeNames(); 273 default: 274 throw new IllegalArgumentException("Invalid scope: " + scope); 275 } 276 } 277 278 @Override 279 public JspWriter getOut() { 280 if (this.out == null) { 281 this.out = new MockJspWriter(this.response); 282 } 283 return this.out; 284 } 285 286 @Override 287 @Deprecated 288 public javax.servlet.jsp.el.ExpressionEvaluator getExpressionEvaluator() { 289 return new MockExpressionEvaluator(this); 290 } 291 292 @Override 293 public ELContext getELContext() { 294 return null; 295 } 296 297 @Override 298 @Deprecated 299 public javax.servlet.jsp.el.VariableResolver getVariableResolver() { 300 return null; 301 } 302 303 @Override 304 public HttpSession getSession() { 305 return this.request.getSession(); 306 } 307 308 @Override 309 public Object getPage() { 310 return this; 311 } 312 313 @Override 314 public ServletRequest getRequest() { 315 return this.request; 316 } 317 318 @Override 319 public ServletResponse getResponse() { 320 return this.response; 321 } 322 323 @Override 324 public Exception getException() { 325 return null; 326 } 327 328 @Override 329 public ServletConfig getServletConfig() { 330 return this.servletConfig; 331 } 332 333 @Override 334 public ServletContext getServletContext() { 335 return this.servletContext; 336 } 337 338 @Override 339 public void forward(String path) throws ServletException, IOException { 340 this.request.getRequestDispatcher(path).forward(this.request, this.response); 341 } 342 343 @Override 344 public void include(String path) throws ServletException, IOException { 345 this.request.getRequestDispatcher(path).include(this.request, this.response); 346 } 347 348 @Override 349 public void include(String path, boolean flush) throws ServletException, IOException { 350 this.request.getRequestDispatcher(path).include(this.request, this.response); 351 if (flush) { 352 this.response.flushBuffer(); 353 } 354 } 355 356 public byte[] getContentAsByteArray() { 357 Assert.state(this.response instanceof MockHttpServletResponse, "MockHttpServletResponse required"); 358 return ((MockHttpServletResponse) this.response).getContentAsByteArray(); 359 } 360 361 public String getContentAsString() throws UnsupportedEncodingException { 362 Assert.state(this.response instanceof MockHttpServletResponse, "MockHttpServletResponse required"); 363 return ((MockHttpServletResponse) this.response).getContentAsString(); 364 } 365 366 @Override 367 public void handlePageException(Exception ex) throws ServletException, IOException { 368 throw new ServletException("Page exception", ex); 369 } 370 371 @Override 372 public void handlePageException(Throwable ex) throws ServletException, IOException { 373 throw new ServletException("Page exception", ex); 374 } 375 376}