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