package hirondelle.fish.test.doubles;
import java.io.*;
import java.util.*;
import java.text.SimpleDateFormat;
import hirondelle.web4j.util.Util;
import hirondelle.web4j.util.Args;
import hirondelle.web4j.model.ModelUtil;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
public final class FakeResponse implements HttpServletResponse {
public String getFinalResponse(String aEncoding){
return fStream.getString(aEncoding);
}
public byte[] getFinalResponseAsBytes(){
return fStream.getBytes();
}
public List<Cookie> getCookies(){ return fCookies; }
public int getStatus() { return fStatusCode; }
public List<Header> getHeaders() { return fHeaders; }
public String getCharacterEncoding() { return fCharacterEncoding; }
public void setCharacterEncoding(String aEncoding) {
if( ! fIsCommitted && ! fHasCalledWriter ) {
Args.checkForContent(aEncoding);
fCharacterEncoding = aEncoding;
}
}
public String getContentType() { return fContentType; }
public void setContentType(String aContentType) {
if( ! fIsCommitted ) {
Args.checkForContent(aContentType);
StringTokenizer parser = new StringTokenizer(aContentType, ";");
String contentType = parser.nextToken();
String charEncoding = parser.nextToken().trim().substring("charset=".length());
fContentType = aContentType; if( ! fHasCalledWriter && Util.textHasContent(charEncoding) ) {
setCharacterEncoding(charEncoding);
}
}
}
public Locale getLocale() { return fLocale; }
public void setLocale(Locale aLocale) {
if( ! fIsCommitted ) {
fLocale = aLocale;
}
}
public ServletOutputStream getOutputStream() throws IOException {
if(fHasCalledWriter) throw new IllegalStateException("Cannot use both Stream and Writer.");
fHasCalledStream = true;
fStream = new FakeServletOutputStream(this);
return fStream;
}
public PrintWriter getWriter() throws IOException {
if(fHasCalledStream) throw new IllegalStateException("Cannot use both Stream and Writer.");
fHasCalledWriter = true;
fStream = new FakeServletOutputStream(this);
fWriter = new PrintWriter(new OutputStreamWriter(fStream, fCharacterEncoding));
return fWriter;
}
public void setContentLength(int aLength) { }
public int getBufferSize() { return fBufferSize; }
public void setBufferSize(int aBufferSize) { fBufferSize = aBufferSize; }
public void flushBuffer() throws IOException { }
public void resetBuffer() { }
public boolean isCommitted() { return fIsCommitted; }
public void reset() { }
public void addCookie(Cookie aCookie) {
fCookies.add(aCookie);
}
public void setStatus(int aStatusCode) {
fStatusCode = aStatusCode;
}
public void setStatus(int aStatusCode, String aStatusMessage) { }
public boolean containsHeader(String aName) {
boolean result = false;
Args.checkForContent(aName);
for(Header header : fHeaders){
if ( aName.equals(header.getName()) ){
result = true;
break;
}
}
return result;
}
public void addHeader(String aName, String aValue) {
fHeaders.add(new Header(aName, aValue));
}
public void setHeader(String aName, String aValue) {
Args.checkForContent(aName);
Args.checkForContent(aValue);
if( containsHeader(aName) ){
replaceExistingHeader(aName, aValue);
}
else {
addHeader(aName, aValue);
}
}
public void addIntHeader(String aName, int aValue) {
addHeader(aName, new Integer(aValue).toString());
}
public void setIntHeader(String aName, int aValue) {
setHeader(aName, new Integer(aValue).toString());
}
public void addDateHeader(String aName, long aValue) {
String date = new SimpleDateFormat(PATTERN_RFC1123).format(new Date(aValue));
addHeader(aName, date);
}
public void setDateHeader(String aName, long aValue) {
String date = new SimpleDateFormat(PATTERN_RFC1123).format(new Date(aValue));
setHeader(aName, date);
}
public String encodeURL(String aURL) { return aURL; }
public String encodeRedirectURL(String aURL) { return aURL; }
public String encodeUrl(String arg0) { return null; }
public String encodeRedirectUrl(String arg0) { return null; }
public void sendError(int aStatusCode) throws IOException {
if(fIsCommitted) throw new IllegalStateException("Cannot set status after response is committed.");
fStatusCode = aStatusCode;
}
public void sendError(int aStatusCode, String aMessage) throws IOException {
if(fIsCommitted) throw new IllegalStateException("Cannot set status after response is committed.");
fStatusCode = aStatusCode;
}
public void sendRedirect(String aLocation) throws IOException {
if(fIsCommitted) throw new IllegalStateException("Cannot send redirect after response is committed.");
}
public static final class Header{
Header(String aName, String aValue){
Args.checkForContent(aName);
Args.checkForContent(aValue);
fName = aName;
fValue = aValue;
}
public String getName() { return fName; }
public String getValue() { return fValue; }
@Override public String toString() {
return ModelUtil.toStringFor(this);
}
private final String fName;
private final String fValue;
}
private String fCharacterEncoding = "ISO-8859-1";
private String fContentType;
private Locale fLocale = Locale.ENGLISH;
private FakeServletOutputStream fStream;
private PrintWriter fWriter;
private boolean fHasCalledStream;
private boolean fHasCalledWriter;
private boolean fIsCommitted;
private int fBufferSize;
private List<Cookie> fCookies = new ArrayList<Cookie>();
private int fStatusCode;
private List<Header> fHeaders = new ArrayList<Header>();
private static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
private static final class FakeServletOutputStream extends ServletOutputStream{
FakeServletOutputStream(FakeResponse aFakeResponse){
fOutput = new ByteArrayOutputStream(1024);
fFakeResponse = aFakeResponse;
}
@Override public void write(int aByte) throws IOException {
fOutput.write(aByte);
fFakeResponse.fIsCommitted = true;
}
byte[] getBytes(){
return fOutput.toByteArray();
}
String getString(String aEncoding){
String result = null;
try {
result = fOutput.toString(aEncoding);
}
catch (UnsupportedEncodingException ex){
throw new IllegalArgumentException("Unsupported encoding: " + Util.quote(aEncoding));
}
return result;
}
private ByteArrayOutputStream fOutput;
private FakeResponse fFakeResponse;
}
private void replaceExistingHeader(String aName, String aValue){
if( ! containsHeader(aName) ) {
throw new IllegalArgumentException("Cannot replace header, since does not exist.");
}
Iterator<Header> iter = fHeaders.iterator();
while ( iter.hasNext() ) {
Header header = iter.next();
if( header.getName().equals(aName)) {
iter.remove();
}
}
addHeader(aName, aValue);
}
}