001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.mock; 018 019import static org.apache.juneau.common.utils.Utils.*; 020import static org.apache.juneau.internal.CollectionUtils.map; 021 022import java.io.*; 023import java.util.*; 024 025import org.apache.juneau.internal.*; 026import org.apache.juneau.rest.util.*; 027 028import jakarta.servlet.*; 029import jakarta.servlet.http.*; 030 031/** 032 * An implementation of {@link HttpServletResponse} for mocking purposes. 033 * 034 * <h5 class='section'>See Also:</h5><ul> 035 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestMockBasics">juneau-rest-mock Basics</a> 036 * </ul> 037*/ 038public class MockServletResponse implements HttpServletResponse { 039 040 private String characterEncoding = "UTF-8"; 041 private ByteArrayOutputStream baos = new ByteArrayOutputStream(); 042 private int bufferSize; 043 private Locale locale; 044 private int sc; 045 private String msg; 046 private Map<String,String[]> headerMap = map(); 047 048 /** 049 * Creates a new servlet response. 050 * 051 * @return A new response. 052 */ 053 public static MockServletResponse create() { 054 return new MockServletResponse(); 055 } 056 057 /** 058 * Returns the response message. 059 * 060 * @return The response message. 061 */ 062 public String getMessage() { 063 return msg; 064 } 065 066 @Override /* HttpServletResponse */ 067 public String getCharacterEncoding() { 068 return characterEncoding ; 069 } 070 071 @Override /* HttpServletResponse */ 072 public String getContentType() { 073 return getHeader("Content-Type"); 074 } 075 076 @Override /* HttpServletResponse */ 077 public ServletOutputStream getOutputStream() throws IOException { 078 return new FinishableServletOutputStream(baos); 079 } 080 081 @Override /* HttpServletResponse */ 082 public PrintWriter getWriter() throws IOException { 083 return new PrintWriter(new OutputStreamWriter(getOutputStream(), characterEncoding)); 084 } 085 086 @Override /* HttpServletResponse */ 087 public void setCharacterEncoding(String charset) { 088 this.characterEncoding = charset; 089 updateContentTypeHeader(); 090 } 091 092 private void updateContentTypeHeader() { 093 String contentType = getContentType(); 094 String charset = characterEncoding; 095 if (contentType != null && charset != null) { 096 if (contentType.indexOf("charset=") != -1) 097 contentType = contentType.replaceAll("\\;\\s*charset=.*", ""); 098 if (! "UTF-8".equalsIgnoreCase(charset)) 099 contentType = contentType + ";charset=" + charset; 100 header("Content-Type", contentType); 101 } 102 } 103 104 @Override /* HttpServletResponse */ 105 public void setContentLength(int len) { 106 header("Content-Length", String.valueOf(len)); 107 } 108 109 @Override /* HttpServletResponse */ 110 public void setContentLengthLong(long len) { 111 header("Content-Length", String.valueOf(len)); 112 } 113 114 @Override /* HttpServletResponse */ 115 public void setContentType(String type) { 116 setHeader("Content-Type", type); 117 updateContentTypeHeader(); 118 } 119 120 @Override /* HttpServletResponse */ 121 public void setBufferSize(int size) { 122 this.bufferSize = size; 123 } 124 125 @Override /* HttpServletResponse */ 126 public int getBufferSize() { 127 return bufferSize; 128 } 129 130 @Override /* HttpServletResponse */ 131 public void flushBuffer() throws IOException { 132 } 133 134 @Override /* HttpServletResponse */ 135 public void resetBuffer() { 136 } 137 138 @Override /* HttpServletResponse */ 139 public boolean isCommitted() { 140 return false; 141 } 142 143 @Override /* HttpServletResponse */ 144 public void reset() { 145 } 146 147 @Override /* HttpServletResponse */ 148 public void setLocale(Locale loc) { 149 this.locale = loc; 150 } 151 152 @Override /* HttpServletResponse */ 153 public Locale getLocale() { 154 return locale; 155 } 156 157 @Override /* HttpServletResponse */ 158 public void addCookie(Cookie cookie) { 159 } 160 161 @Override /* HttpServletResponse */ 162 public boolean containsHeader(String name) { 163 return getHeader(name) != null; 164 } 165 166 @Override /* HttpServletResponse */ 167 public String encodeURL(String url) { 168 return null; 169 } 170 171 @Override /* HttpServletResponse */ 172 public String encodeRedirectURL(String url) { 173 return null; 174 } 175 176 @Override /* HttpServletResponse */ 177 public void sendError(int sc, String msg) throws IOException { 178 this.sc = sc; 179 this.msg = msg; 180 } 181 182 @Override /* HttpServletResponse */ 183 public void sendError(int sc) throws IOException { 184 this.sc = sc; 185 } 186 187 @Override /* HttpServletResponse */ 188 public void sendRedirect(String location) throws IOException { 189 this.sc = 302; 190 headerMap.put("Location", new String[] {location}); 191 } 192 193 @Override /* HttpServletResponse */ 194 public void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException { 195 this.sc = sc; 196 headerMap.put("Location", new String[] {location}); 197 } 198 199 @Override /* HttpServletResponse */ 200 public void setDateHeader(String name, long date) { 201 headerMap.put(name, new String[] {DateUtils.formatDate(new Date(date), DateUtils.PATTERN_RFC1123)}); 202 } 203 204 @Override /* HttpServletResponse */ 205 public void addDateHeader(String name, long date) { 206 headerMap.put(name, new String[] {DateUtils.formatDate(new Date(date), DateUtils.PATTERN_RFC1123)}); 207 } 208 209 @Override /* HttpServletResponse */ 210 public void setHeader(String name, String value) { 211 headerMap.put(name, new String[] {value}); 212 } 213 214 @Override /* HttpServletResponse */ 215 public void addHeader(String name, String value) { 216 headerMap.put(name, new String[] {value}); 217 } 218 219 /** 220 * Fluent setter for {@link #setHeader(String,String)}. 221 * 222 * @param name The header name. 223 * @param value The new header value. 224 * @return This object. 225 */ 226 public MockServletResponse header(String name, String value) { 227 setHeader(name, value); 228 return this; 229 } 230 231 @Override /* HttpServletResponse */ 232 public void setIntHeader(String name, int value) { 233 headerMap.put(name, new String[] {String.valueOf(value)}); 234 } 235 236 @Override /* HttpServletResponse */ 237 public void addIntHeader(String name, int value) { 238 headerMap.put(name, new String[] {String.valueOf(value)}); 239 } 240 241 @Override /* HttpServletResponse */ 242 public void setStatus(int sc) { 243 this.sc = sc; 244 } 245 246 /** 247 * Fluent setter for {@link #setStatus(int)}. 248 * 249 * @param value The new property value. 250 * @return This object. 251 */ 252 public MockServletResponse status(int value) { 253 setStatus(value); 254 return this; 255 } 256 257 @Override /* HttpServletResponse */ 258 public int getStatus() { 259 return sc; 260 } 261 262 @Override /* HttpServletResponse */ 263 public String getHeader(String name) { 264 String[] s = headerMap.get(name); 265 return s == null || s.length == 0 ? null : s[0]; 266 } 267 268 @Override /* HttpServletResponse */ 269 public Collection<String> getHeaders(String name) { 270 String[] s = headerMap.get(name); 271 return s == null ? Collections.emptyList() : u(alist(s)); 272 } 273 274 @Override /* HttpServletResponse */ 275 public Collection<String> getHeaderNames() { 276 return headerMap.keySet(); 277 } 278 279 byte[] getContent() throws IOException { 280 baos.flush(); 281 return baos.toByteArray(); 282 } 283 284 Map<String,String[]> getHeaders() { 285 return headerMap; 286 } 287 288}