com.phloc.web.mock.MockHttpServletResponse Maven / Gradle / Ivy
/**
* Copyright (C) 2006-2015 phloc systems
* http://www.phloc.com
* office[at]phloc[dot]com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.phloc.web.mock;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.phloc.commons.IHasLocale;
import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.annotations.ReturnsMutableCopy;
import com.phloc.commons.charset.CCharset;
import com.phloc.commons.charset.CharsetManager;
import com.phloc.commons.collections.ArrayHelper;
import com.phloc.commons.collections.ContainerHelper;
import com.phloc.commons.collections.multimap.IMultiMapSetBased;
import com.phloc.commons.collections.multimap.MultiHashMapLinkedHashSetBased;
import com.phloc.commons.io.streams.NonBlockingByteArrayOutputStream;
import com.phloc.commons.io.streams.StreamUtils;
import com.phloc.commons.mime.IMimeType;
import com.phloc.commons.mime.MimeTypeParser;
import com.phloc.commons.mime.MimeTypeParserException;
import com.phloc.commons.mime.MimeTypeUtils;
import com.phloc.commons.string.StringHelper;
import com.phloc.commons.system.SystemHelper;
import com.phloc.web.CWeb;
// ESCA-JAVA0116:
/**
* Mock implementation of {@link HttpServletResponse}.
*
* @author Philip Helger
*/
@NotThreadSafe
public class MockHttpServletResponse implements HttpServletResponse, IHasLocale
{
public static final int DEFAULT_SERVER_PORT = CWeb.DEFAULT_PORT_HTTP;
public static final String DEFAULT_CHARSET_NAME = CCharset.CHARSET_UTF_8;
public static final Charset DEFAULT_CHARSET_OBJ = CCharset.CHARSET_UTF_8_OBJ;
private static final int DEFAULT_BUFFER_SIZE = 4096;
private static final Logger s_aLogger = LoggerFactory.getLogger (MockHttpServletResponse.class);
private boolean m_bOutputStreamAccessAllowed = true;
private boolean m_bWriterAccessAllowed = true;
private Charset m_aCharacterEncoding = DEFAULT_CHARSET_OBJ;
private final NonBlockingByteArrayOutputStream m_aContent = new NonBlockingByteArrayOutputStream ();
private final ServletOutputStream m_aOS = new ServletOutputStream ()
{
@Override
public void write (final int b) throws IOException
{
MockHttpServletResponse.this.m_aContent.write (b);
super.flush ();
_setCommittedIfBufferSizeExceeded ();
}
@Override
public void flush () throws IOException
{
super.flush ();
setCommitted (true);
}
};
private PrintWriter m_aWriter;
private int m_nContentLength = 0;
private String m_sContentType;
private int m_nBufferSize = DEFAULT_BUFFER_SIZE;
private boolean m_bCommitted;
private Locale m_aLocale = Locale.getDefault ();
// HttpServletResponse properties
private final List m_aCookies = new ArrayList ();
private final IMultiMapSetBased m_aHeaders = new MultiHashMapLinkedHashSetBased ();
private int m_nStatus = HttpServletResponse.SC_OK;
private String m_sErrorMessage;
private String m_sRedirectedUrl;
private String m_sForwardedUrl;
private String m_sIncludedUrl;
private String m_sEncodeUrlSuffix;
private String m_sEncodeRedirectUrlSuffix;
public MockHttpServletResponse ()
{}
/**
* Set whether {@link #getOutputStream()} access is allowed.
*
* Default is true
.
*
* @param bOutputStreamAccessAllowed
*/
public void setOutputStreamAccessAllowed (final boolean bOutputStreamAccessAllowed)
{
m_bOutputStreamAccessAllowed = bOutputStreamAccessAllowed;
}
/**
* @return whether {@link #getOutputStream()} access is allowed.
*/
public boolean isOutputStreamAccessAllowed ()
{
return m_bOutputStreamAccessAllowed;
}
/**
* Set whether {@link #getWriter()} access is allowed.
*
* Default is true
.
*/
public void setWriterAccessAllowed (final boolean bWriterAccessAllowed)
{
m_bWriterAccessAllowed = bWriterAccessAllowed;
}
/**
* @return whether {@link #getOutputStream()} access is allowed.
*/
public boolean isWriterAccessAllowed ()
{
return m_bWriterAccessAllowed;
}
public void setCharacterEncoding (@Nullable final String sCharacterEncoding)
{
setCharacterEncoding (sCharacterEncoding == null ? null : CharsetManager.getCharsetFromName (sCharacterEncoding));
}
public void setCharacterEncoding (@Nullable final Charset aCharacterEncoding)
{
m_aCharacterEncoding = aCharacterEncoding;
}
@Nullable
public String getCharacterEncoding ()
{
return m_aCharacterEncoding == null ? null : m_aCharacterEncoding.name ();
}
@Nullable
public Charset getCharacterEncodingObj ()
{
return m_aCharacterEncoding;
}
@Nonnull
@Nonempty
@Deprecated
public String getCharacterEncodingOrDefault ()
{
String ret = getCharacterEncoding ();
if (ret == null)
ret = SystemHelper.getSystemCharsetName ();
return ret;
}
@Nonnull
public Charset getCharacterEncodingObjOrDefault ()
{
Charset ret = getCharacterEncodingObj ();
if (ret == null)
ret = SystemHelper.getSystemCharset ();
return ret;
}
@Nonnull
public ServletOutputStream getOutputStream ()
{
if (!m_bOutputStreamAccessAllowed)
throw new IllegalStateException ("OutputStream access not allowed");
return m_aOS;
}
@Nonnull
public PrintWriter getWriter ()
{
if (!m_bWriterAccessAllowed)
throw new IllegalStateException ("Writer access not allowed");
if (m_aWriter == null)
{
final Writer aWriter = StreamUtils.createWriter (m_aContent, getCharacterEncodingObjOrDefault ());
m_aWriter = new ResponsePrintWriter (aWriter);
}
return m_aWriter;
}
@Nonnull
@ReturnsMutableCopy
public byte [] getContentAsByteArray ()
{
flushBuffer ();
return m_aContent.toByteArray ();
}
@Nonnull
public String getContentAsString ()
{
return getContentAsString (getCharacterEncodingOrDefault ());
}
@Nonnull
@Deprecated
public String getContentAsString (@Nonnull @Nonempty final String sCharset)
{
flushBuffer ();
return m_aContent.getAsString (sCharset);
}
@Nonnull
public String getContentAsString (@Nonnull final Charset aCharset)
{
flushBuffer ();
return m_aContent.getAsString (aCharset);
}
public void setContentLength (final int nContentLength)
{
m_nContentLength = nContentLength;
}
public int getContentLength ()
{
return m_nContentLength;
}
public void setContentType (@Nullable final String sContentType)
{
m_sContentType = sContentType;
if (sContentType != null)
{
try
{
final IMimeType aContentType = MimeTypeParser.parseMimeType (sContentType);
final String sEncoding = MimeTypeUtils.getCharsetNameFromMimeType (aContentType);
if (sEncoding != null)
setCharacterEncoding (sEncoding);
}
catch (final MimeTypeParserException ex)
{
s_aLogger.warn ("Passed content type '" + sContentType + "' cannot be parsed as a MIME type");
}
}
}
@Nullable
public String getContentType ()
{
return m_sContentType;
}
public void setBufferSize (final int nBufferSize)
{
m_nBufferSize = nBufferSize;
}
public int getBufferSize ()
{
return m_nBufferSize;
}
public void flushBuffer ()
{
setCommitted (true);
}
/*
* Throws exception if committed!
*/
public void resetBuffer ()
{
if (isCommitted ())
throw new IllegalStateException ("Cannot reset buffer - response is already committed");
m_aContent.reset ();
m_aWriter = null;
}
private void _setCommittedIfBufferSizeExceeded ()
{
final int nBufSize = getBufferSize ();
if (nBufSize > 0 && m_aContent.size () > nBufSize)
setCommitted (true);
}
public void setCommitted (final boolean bCommitted)
{
m_bCommitted = bCommitted;
}
public boolean isCommitted ()
{
return m_bCommitted;
}
/*
* Throws exception if committed!
*/
public void reset ()
{
resetBuffer ();
m_aCharacterEncoding = null;
m_nContentLength = 0;
m_sContentType = null;
m_aLocale = null;
m_aCookies.clear ();
m_aHeaders.clear ();
m_nStatus = HttpServletResponse.SC_OK;
m_sErrorMessage = null;
}
public void setLocale (@Nullable final Locale aLocale)
{
m_aLocale = aLocale;
}
@Nullable
public Locale getLocale ()
{
return m_aLocale;
}
// ---------------------------------------------------------------------
// HttpServletResponse interface
// ---------------------------------------------------------------------
public void addCookie (@Nonnull final Cookie aCookie)
{
ValueEnforcer.notNull (aCookie, "Cookie");
m_aCookies.add (aCookie);
}
@Nonnull
@ReturnsMutableCopy
public Cookie [] getCookies ()
{
return ArrayHelper.newArray (m_aCookies, Cookie.class);
}
@Nullable
public Cookie getCookie (@Nonnull final String sName)
{
ValueEnforcer.notNull (sName, "Name");
for (final Cookie aCookie : m_aCookies)
if (sName.equals (aCookie.getName ()))
return aCookie;
return null;
}
@Nullable
private static String _unifyHeaderName (@Nullable final String sName)
{
// Same as in MockHttpServletRequest
return sName == null ? null : sName.toLowerCase (Locale.US);
}
public boolean containsHeader (@Nullable final String sName)
{
return m_aHeaders.containsKey (_unifyHeaderName (sName));
}
/**
* Return the names of all specified headers as a Set of Strings.
*
* @return the Set
of header name Strings
, or an
* empty Set
if none
*/
@Nonnull
@ReturnsMutableCopy
public Set getHeaderNames ()
{
return ContainerHelper.newSet (m_aHeaders.keySet ());
}
/**
* Return the primary value for the given header, if any.
*
* Will return the first value in case of multiple values.
*
* @param sName
* the name of the header
* @return the associated header value, or null if none
*/
@Nullable
public Object getHeader (@Nullable final String sName)
{
final List