001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.mock;
014
015import static org.apache.juneau.internal.StringUtils.*;
016
017import java.io.*;
018import java.text.*;
019import java.util.*;
020import java.util.regex.*;
021
022import javax.servlet.*;
023import javax.servlet.http.*;
024
025import org.apache.juneau.internal.*;
026import org.apache.juneau.rest.util.*;
027import org.apache.juneau.utils.*;
028
029/**
030 * An implementation of {@link HttpServletResponse} for mocking purposes.
031 *
032 * @deprecated Use <c>org.apache.juneau.rest.mock2</c>
033*/
034@Deprecated
035public class MockServletResponse implements HttpServletResponse, MockHttpResponse {
036
037   private String characterEncoding = "UTF-8";
038   private ByteArrayOutputStream baos = new ByteArrayOutputStream();
039   private long contentLength = 0;
040   private int bufferSize = 0;
041   private Locale locale;
042   private int sc;
043   private String msg;
044   private Map<String,String[]> headerMap = new LinkedHashMap<>();
045
046
047   /**
048    * Creates a new servlet response.
049    *
050    * @return A new response.
051    */
052   public static MockServletResponse create() {
053      return new MockServletResponse();
054   }
055
056   /**
057    * Returns the content length.
058    *
059    * @return The content length.
060    */
061   public long getContentLength() {
062      return contentLength;
063   }
064
065   /**
066    * Returns the response message.
067    *
068    * @return The response message.
069    */
070   @Override /* MockHttpResponse */
071   public String getMessage() {
072      return msg;
073   }
074
075   @Override /* HttpServletResponse */
076   public String getCharacterEncoding() {
077      return characterEncoding ;
078   }
079
080   @Override /* HttpServletResponse */
081   public String getContentType() {
082      return getHeader("Content-Type");
083   }
084
085   @Override /* HttpServletResponse */
086   public ServletOutputStream getOutputStream() throws IOException {
087      return new FinishableServletOutputStream(baos);
088   }
089
090   @Override /* HttpServletResponse */
091   public PrintWriter getWriter() throws IOException {
092      return new PrintWriter(new OutputStreamWriter(getOutputStream(), characterEncoding));
093   }
094
095   @Override /* HttpServletResponse */
096   public void setCharacterEncoding(String charset) {
097      this.characterEncoding = charset;
098   }
099
100   @Override /* HttpServletResponse */
101   public void setContentLength(int len) {
102      this.contentLength = len;
103   }
104
105   @Override /* HttpServletResponse */
106   public void setContentLengthLong(long len) {
107      this.contentLength = len;
108   }
109
110   @Override /* HttpServletResponse */
111   public void setContentType(String type) {
112      setHeader("Content-Type", type);
113   }
114
115   @Override /* HttpServletResponse */
116   public void setBufferSize(int size) {
117      this.bufferSize = size;
118   }
119
120   @Override /* HttpServletResponse */
121   public int getBufferSize() {
122      return bufferSize;
123   }
124
125   @Override /* HttpServletResponse */
126   public void flushBuffer() throws IOException {
127   }
128
129   @Override /* HttpServletResponse */
130   public void resetBuffer() {
131   }
132
133   @Override /* HttpServletResponse */
134   public boolean isCommitted() {
135      return false;
136   }
137
138   @Override /* HttpServletResponse */
139   public void reset() {
140   }
141
142   @Override /* HttpServletResponse */
143   public void setLocale(Locale loc) {
144      this.locale = loc;
145   }
146
147   @Override /* HttpServletResponse */
148   public Locale getLocale() {
149      return locale;
150   }
151
152   @Override /* HttpServletResponse */
153   public void addCookie(Cookie cookie) {
154   }
155
156   @Override /* HttpServletResponse */
157   public boolean containsHeader(String name) {
158      return getHeader(name) != null;
159   }
160
161   @Override /* HttpServletResponse */
162   public String encodeURL(String url) {
163      return null;
164   }
165
166   @Override /* HttpServletResponse */
167   public String encodeRedirectURL(String url) {
168      return null;
169   }
170
171   @Override /* HttpServletResponse */
172   public String encodeUrl(String url) {
173      return null;
174   }
175
176   @Override /* HttpServletResponse */
177   public String encodeRedirectUrl(String url) {
178      return null;
179   }
180
181   @Override /* HttpServletResponse */
182   public void sendError(int sc, String msg) throws IOException {
183      this.sc = sc;
184      this.msg = msg;
185   }
186
187   @Override /* HttpServletResponse */
188   public void sendError(int sc) throws IOException {
189      this.sc = sc;
190   }
191
192   @Override /* HttpServletResponse */
193   public void sendRedirect(String location) throws IOException {
194      this.sc = 302;
195      headerMap.put("Location", new String[] {location});
196   }
197
198   @Override /* HttpServletResponse */
199   public void setDateHeader(String name, long date) {
200      headerMap.put(name, new String[] {DateUtils.formatDate(new Date(date), DateUtils.PATTERN_RFC1123)});
201   }
202
203   @Override /* HttpServletResponse */
204   public void addDateHeader(String name, long date) {
205      headerMap.put(name, new String[] {DateUtils.formatDate(new Date(date), DateUtils.PATTERN_RFC1123)});
206   }
207
208   @Override /* HttpServletResponse */
209   public void setHeader(String name, String value) {
210      headerMap.put(name, new String[] {value});
211   }
212
213   @Override /* HttpServletResponse */
214   public void addHeader(String name, String value) {
215      headerMap.put(name, new String[] {value});
216   }
217
218   @Override /* HttpServletResponse */
219   public void setIntHeader(String name, int value) {
220      headerMap.put(name, new String[] {String.valueOf(value)});
221   }
222
223   @Override /* HttpServletResponse */
224   public void addIntHeader(String name, int value) {
225      headerMap.put(name, new String[] {String.valueOf(value)});
226   }
227
228   @Override /* HttpServletResponse */
229   public void setStatus(int sc) {
230      this.sc = sc;
231   }
232
233   @Override /* HttpServletResponse */
234   public void setStatus(int sc, String sm) {
235      this.sc = sc;
236      this.msg = sm;
237   }
238
239   @Override /* HttpServletResponse */
240   public int getStatus() {
241      return sc;
242   }
243
244   @Override /* HttpServletResponse */
245   public String getHeader(String name) {
246      String[] s = headerMap.get(name);
247      return s == null || s.length == 0 ? null : s[0];
248   }
249
250   @Override /* HttpServletResponse */
251   public Collection<String> getHeaders(String name) {
252      String[] s = headerMap.get(name);
253      return s == null ? Collections.emptyList() : Arrays.asList(s);
254   }
255
256   @Override /* HttpServletResponse */
257   public Collection<String> getHeaderNames() {
258      return headerMap.keySet();
259   }
260
261   /**
262    * Returns the body of the request as a string.
263    *
264    * @return The body of the request as a string.
265    */
266   public String getBodyAsString() {
267      try {
268         return baos.toString("UTF-8");
269      } catch (UnsupportedEncodingException e) {
270         throw new RuntimeException(e);
271      }
272   }
273
274   /**
275    * Throws an {@link AssertionError} if the response status does not match the expected status.
276    *
277    * @param status The expected status.
278    * @return This object (for method chaining).
279    * @throws AssertionError Thrown if status does not match.
280    */
281   public MockServletResponse assertStatus(int status) throws AssertionError {
282      if (getStatus() != status)
283         throw new MockAssertionError("Response did not have the expected status.\n\tExpected=[{0}]\n\tActual=[{1}]", status, getStatus());
284      return this;
285   }
286
287   /**
288    * Throws an {@link AssertionError} if the response body does not contain the expected text.
289    *
290    * @param text The expected text of the body.
291    * @return This object (for method chaining).
292    * @throws AssertionError Thrown if the body does not contain the expected text.
293    */
294   public MockServletResponse assertBody(String text) throws AssertionError {
295      if (! StringUtils.isEquals(text, getBodyAsString()))
296         throw new MockAssertionError("Response did not have the expected text.\n\tExpected=[{0}]\n\tActual=[{1}]", text, getBodyAsString());
297      return this;
298   }
299
300   /**
301    * Throws an {@link AssertionError} if the response body does not contain all of the expected substrings.
302    *
303    * @param substrings The expected substrings.
304    * @return This object (for method chaining).
305    * @throws AssertionError Thrown if the body does not contain one or more of the expected substrings.
306    */
307   public MockServletResponse assertBodyContains(String...substrings) throws AssertionError {
308      String text = getBodyAsString();
309      for (String substring : substrings)
310         if (! contains(text, substring))
311            throw new MockAssertionError("Response did not have the expected substring.\n\tExpected=[{0}]\n\tBody=[{1}]", substring, text);
312      return this;
313   }
314
315   /**
316    * Throws an {@link AssertionError} if the response body does not match the specified pattern.
317    *
318    * <p>
319    * A pattern is a simple string containing <js>"*"</js> to represent zero or more arbitrary characters.
320    *
321    * @param pattern The pattern to match against.
322    * @return This object (for method chaining).
323    * @throws AssertionError Thrown if the body does not match the specified pattern.
324    */
325   public MockServletResponse assertBodyMatches(String pattern) throws AssertionError {
326      String text = getBodyAsString();
327      if (! getMatchPattern(pattern).matcher(text).matches())
328         throw new MockAssertionError("Response did not match expected pattern.\n\tPattern=[{0}]\n\tBody=[{1}]", pattern, text);
329      return this;
330   }
331
332   /**
333    * Throws an {@link AssertionError} if the response body does not match the specified regular expression.
334    *
335    * <p>
336    * A pattern is a simple string containing <js>"*"</js> to represent zero or more arbitrary characters.
337    *
338    * @param regExp The regular expression to match against.
339    * @return This object (for method chaining).
340    * @throws AssertionError Thrown if the body does not match the specified regular expression.
341    */
342   public MockServletResponse assertBodyMatchesRE(String regExp) throws AssertionError {
343      String text = getBodyAsString();
344      if (! Pattern.compile(regExp).matcher(text).matches())
345         throw new MockAssertionError("Response did not match expected regular expression.\n\tRegExp=[{0}]\n\tBody=[{1}]", regExp, text);
346      return this;
347   }
348
349   /**
350    * Throws an {@link AssertionError} if the response does not contain the expected character encoding.
351    *
352    * @param value The expected character encoding.
353    * @return This object (for method chaining).
354    * @throws AssertionError Thrown if the response does not contain the expected character encoding.
355    */
356   public MockServletResponse assertCharset(String value) {
357      if (! StringUtils.isEquals(value, getCharacterEncoding()))
358         throw new MockAssertionError("Response did not have the expected character encoding.\n\tExpected=[{0}]\n\tActual=[{1}]", value, getBodyAsString());
359      return this;
360   }
361
362   /**
363    * Throws an {@link AssertionError} if the response does not contain the expected header value.
364    *
365    * @param name The header name.
366    * @param value The expected header value.
367    * @return This object (for method chaining).
368    * @throws AssertionError Thrown if the response does not contain the expected header value.
369    */
370   public MockServletResponse assertHeader(String name, String value) {
371      if (! StringUtils.isEquals(value, getHeader(name)))
372         throw new MockAssertionError("Response did not have the expected value for header {0}.\n\tExpected=[{1}]\n\tActual=[{2}]", name, value, getHeader(name));
373      return this;
374   }
375
376   /**
377    * Throws an {@link AssertionError} if the response header does not contain all of the expected substrings.
378    *
379    * @param name The header name.
380    * @param substrings The expected substrings.
381    * @return This object (for method chaining).
382    * @throws AssertionError Thrown if the header does not contain one or more of the expected substrings.
383    */
384   public MockServletResponse assertHeaderContains(String name, String...substrings) {
385      String text = getHeader(name);
386      for (String substring : substrings)
387         if (! contains(text, substring))
388            throw new MockAssertionError("Response did not have the expected substring in header {0}.\n\tExpected=[{1}]\n\tHeader=[{2}]", name, substring, text);
389      return this;
390   }
391
392   /**
393    * Returns the body of the request.
394    *
395    * @return The body of the request.
396    */
397   @Override /* MockHttpResponse */
398   public byte[] getBody() {
399      return baos.toByteArray();
400   }
401
402   @Override /* MockHttpResponse */
403   public Map<String,String[]> getHeaders() {
404      return headerMap;
405   }
406
407   private static class MockAssertionError extends AssertionError {
408      private static final long serialVersionUID = 1L;
409
410      MockAssertionError(String msg, Object...args) {
411         super(MessageFormat.format(msg, args));
412         System.err.println(getMessage());  // NOT DEBUG
413      }
414   }
415}