001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2005-2011 Pentaho and others 008// All Rights Reserved. 009*/ 010package mondrian.tui; 011 012import java.io.*; 013import java.text.DateFormat; 014import java.text.SimpleDateFormat; 015import java.util.*; 016import javax.servlet.ServletOutputStream; 017import javax.servlet.http.Cookie; 018import javax.servlet.http.HttpServletResponse; 019 020/** 021 * This is a partial implementation of the HttpServletResponse where just 022 * enough is present to allow for communication between Mondrian's 023 * XMLA code and other code in the same JVM. 024 * Currently it is used in both the CmdRunner and in XMLA JUnit tests. 025 * <p> 026 * If you need to add to this implementation, please do so. 027 * 028 * @author Richard M. Emberson 029 */ 030public class MockHttpServletResponse implements HttpServletResponse { 031 032 public static final String DATE_FORMAT_HEADER = 033 "EEE, d MMM yyyy HH:mm:ss Z"; 034 035 static class MockServletOutputStream extends ServletOutputStream { 036 private ByteArrayOutputStream buffer; 037 private String encoding; 038 039 public MockServletOutputStream(int size) { 040 this(size, "ISO-8859-1"); 041 } 042 043 public MockServletOutputStream(int size, String encoding) { 044 buffer = new ByteArrayOutputStream(size); 045 this.encoding = encoding; 046 } 047 048 public void setEncoding(String encoding) { 049 this.encoding = encoding; 050 } 051 052 public void write(int value) throws IOException { 053 buffer.write(value); 054 } 055 056 public String getContent() throws IOException { 057 try { 058 buffer.flush(); 059 return buffer.toString(encoding); 060 } catch (IOException exc) { 061 throw exc; 062 } 063 } 064 065 public byte[] getBinaryContent() throws IOException { 066 try { 067 buffer.flush(); 068 return buffer.toByteArray(); 069 } catch (IOException exc) { 070 throw exc; 071 } 072 } 073 074 public void clearContent() { 075 buffer = new ByteArrayOutputStream(); 076 } 077 } 078 079 080 private PrintWriter writer; 081 private Locale locale; 082 private String charEncoding; 083 private List<Cookie> cookies; 084 private MockServletOutputStream outputStream; 085 private int statusCode; 086 private boolean isCommited; 087 private String errorMsg; 088 private int errorCode; 089 private boolean wasErrorSent; 090 private boolean wasRedirectSent; 091 private int bufferSize; 092 private final Map<String, List<String>> headers; 093 094 public MockHttpServletResponse() { 095 this.isCommited = false; 096 this.cookies = Collections.emptyList(); 097 this.bufferSize = 8192; 098 this.charEncoding = "ISO-8859-1"; 099 this.errorCode = SC_OK; 100 this.statusCode = SC_OK; 101 this.headers = new HashMap<String, List<String>>(); 102 this.outputStream = new MockServletOutputStream(bufferSize); 103 } 104 105 /** 106 * Returns the name of the charset used for the MIME body sent in this 107 * response. 108 * 109 */ 110 public String getCharacterEncoding() { 111 return charEncoding; 112 } 113 114 /** 115 * Returns a ServletOutputStream suitable for writing binary data in the 116 * response. 117 * 118 * @throws IOException 119 */ 120 public ServletOutputStream getOutputStream() throws IOException { 121 return outputStream; 122 } 123 124 /** 125 * Returns a PrintWriter object that can send character text to the client. 126 * 127 * @throws IOException 128 */ 129 public PrintWriter getWriter() throws IOException { 130 if (writer == null) { 131 writer = new PrintWriter(new OutputStreamWriter( 132 outputStream, charEncoding), true); 133 } 134 135 return writer; 136 } 137 138 public void setCharacterEncoding(String charEncoding) { 139 this.charEncoding = charEncoding; 140 this.outputStream.setEncoding(charEncoding); 141 } 142 143 /** 144 * Sets the length of the content body in the response In HTTP servlets, 145 * this method sets the HTTP Content-Length header. 146 * 147 */ 148 public void setContentLength(int len) { 149 setIntHeader("Content-Length", len); 150 } 151 152 /** 153 * Sets the content type of the response being sent to the client. 154 * 155 */ 156 public void setContentType(String contentType) { 157 setHeader("Content-Type", contentType); 158 } 159 160 /** 161 * Sets the preferred buffer size for the body of the response. 162 * 163 */ 164 public void setBufferSize(int size) { 165 this.bufferSize = size; 166 } 167 168 /** 169 * Returns the actual buffer size used for the response. 170 * 171 */ 172 public int getBufferSize() { 173 return this.bufferSize; 174 } 175 176 /** 177 * Forces any content in the buffer to be written to the client. 178 * 179 * @throws IOException 180 */ 181 public void flushBuffer() throws IOException { 182 if (writer != null) { 183 writer.flush(); 184 } 185 outputStream.flush(); 186 } 187 188 public void resetBuffer() { 189 outputStream.clearContent(); 190 } 191 192 /** 193 * Returns a boolean indicating if the response has been committed. 194 * 195 */ 196 public boolean isCommitted() { 197 return isCommited; 198 } 199 200 /** 201 * Clears any data that exists in the buffer as well as the status code and 202 * headers. 203 */ 204 public void reset() { 205 headers.clear(); 206 resetBuffer(); 207 } 208 209 /** 210 * Sets the locale of the response, setting the headers (including the 211 * Content-Type's charset) as appropriate. 212 * 213 */ 214 public void setLocale(Locale locale) { 215 this.locale = locale; 216 } 217 218 /** 219 * Returns the locale assigned to the response. 220 * 221 */ 222 public Locale getLocale() { 223 return locale; 224 } 225 226 /** 227 * Adds the specified cookie to the response. 228 * 229 */ 230 public void addCookie(Cookie cookie) { 231 if (cookies.isEmpty()) { 232 cookies = new ArrayList<Cookie>(); 233 } 234 cookies.add(cookie); 235 } 236 237 /** 238 * Returns a boolean indicating whether the named response header has 239 * already been set. 240 * 241 */ 242 public boolean containsHeader(String name) { 243 return headers.containsKey(name); 244 } 245 246 /** 247 * Encodes the specified URL by including the session ID in it, or, if 248 * encoding is not needed, returns the URL unchanged. 249 * 250 */ 251 public String encodeURL(String url) { 252 return encode(url); 253 } 254 255 /** 256 * Encodes the specified URL for use in the sendRedirect method or, if 257 * encoding is not needed, returns the URL unchanged. 258 * 259 */ 260 public String encodeRedirectURL(String url) { 261 return encode(url); 262 } 263 264 /** 265 * @deprecated Method encodeUrl is deprecated 266 */ 267 268 public String encodeUrl(String s) { 269 return encodeURL(s); 270 } 271 272 /** 273 * @deprecated Method encodeRedirectUrl is deprecated 274 */ 275 276 public String encodeRedirectUrl(String s) { 277 return encodeRedirectURL(s); 278 } 279 280 /** 281 * Sends an error response to the client using the specified status code 282 * and descriptive message. 283 * 284 */ 285 public void sendError(int code, String msg) throws IOException { 286 this.errorCode = code; 287 this.wasErrorSent = true; 288 this.errorMsg = msg; 289 } 290 291 /** 292 * Sends an error response to the client using the specified status. 293 * 294 */ 295 public void sendError(int code) throws IOException { 296 this.errorCode = code; 297 this.wasErrorSent = true; 298 } 299 300 /** 301 * Sends a temporary redirect response to the client using the specified 302 * redirect location URL. 303 * 304 */ 305 public void sendRedirect(String location) throws IOException { 306 setHeader("Location", location); 307 wasRedirectSent = true; 308 } 309 310 /** 311 * Sets a response header with the given name and date-value. 312 * 313 */ 314 public void setDateHeader(String name, long date) { 315 Date dateValue = new Date(date); 316 String dateString = DateFormat.getDateInstance().format(dateValue); 317 setHeader(name, dateString); 318 } 319 320 /** 321 * Adds a response header with the given name and date-value. 322 * 323 */ 324 public void addDateHeader(String name, long date) { 325 Date dateValue = new Date(date); 326 String dateString = 327 new SimpleDateFormat( 328 DATE_FORMAT_HEADER, Locale.US).format(dateValue); 329 addHeader(name, dateString); 330 } 331 332 /** 333 * Sets a response header with the given name and value. 334 * 335 */ 336 public void setHeader(String name, String value) { 337 List<String> valueList = headers.get(name); 338 if (valueList == null) { 339 valueList = new ArrayList<String>(); 340 headers.put(name, valueList); 341 } 342 valueList.add(value); 343 } 344 345 /** 346 * Adds a response header with the given name and value. 347 * 348 */ 349 public void addHeader(String name, String value) { 350 List<String> valueList = headers.get(name); 351 if (null == valueList) { 352 valueList = new ArrayList<String>(); 353 headers.put(name, valueList); 354 } 355 valueList.add(value); 356 } 357 358 /** 359 * Sets a response header with the given name and integer value. 360 * 361 */ 362 public void setIntHeader(String name, int value) { 363 String stringValue = Integer.toString(value); 364 addHeader(name, stringValue); 365 } 366 367 /** 368 * Adds a response header with the given name and integer value. 369 * 370 */ 371 public void addIntHeader(String name, int value) { 372 String stringValue = Integer.toString(value); 373 addHeader(name, stringValue); 374 } 375 376 /** 377 * Sets the status code for this response. 378 * 379 */ 380 public void setStatus(int status) { 381 this.statusCode = status; 382 } 383 384 /** 385 * @deprecated Method setStatus is deprecated 386 * Deprecated. As of version 2.1, due to ambiguous meaning of the message 387 * parameter. To set a status code use setStatus(int), to send an error with 388 * a description use sendError(int, String). Sets the status code and 389 * message for this response. 390 */ 391 public void setStatus(int status, String s) { 392 setStatus(status); 393 } 394 395 ///////////////////////////////////////////////////////////////////////// 396 // 397 // implementation access 398 // 399 ///////////////////////////////////////////////////////////////////////// 400 public byte[] toByteArray() throws IOException { 401 return outputStream.getBinaryContent(); 402 } 403 404 public String getHeader(String name) { 405 List<String> list = getHeaderList(name); 406 407 return ((list == null) || (list.size() == 0)) 408 ? null 409 : list.get(0); 410 } 411 412 public String getContentType() { 413 return getHeader("Content-Type"); 414 } 415 416 417 ///////////////////////////////////////////////////////////////////////// 418 // 419 // helpers 420 // 421 ///////////////////////////////////////////////////////////////////////// 422 public List<String> getHeaderList(String name) { 423 return headers.get(name); 424 } 425 426 public int getStatusCode() { 427 return statusCode; 428 } 429 430 public int getErrorCode() { 431 return errorCode; 432 } 433 434 public List getCookies() { 435 return cookies; 436 } 437 438 public boolean wasErrorSent() { 439 return wasErrorSent; 440 } 441 442 public boolean wasRedirectSent() { 443 return wasRedirectSent; 444 } 445 446/* 447 protected void clearHeaders() { 448 this.headers.clear(); 449 } 450*/ 451 452 protected String encode(String s) { 453 // TODO 454 return s; 455 } 456 457 458} 459 460// End MockHttpServletResponse.java