/*
* Copyright (C) 2014 Civilian Framework.
*
* Licensed under the Civilian License (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.civilian-framework.org/license.txt
*
* 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 org.civilian.context.test;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Flushable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import javax.servlet.http.Cookie;
import org.civilian.Request;
import org.civilian.Response;
import org.civilian.content.ContentType;
import org.civilian.internal.AbstractResponse;
import org.civilian.internal.ParamList;
import org.civilian.request.CookieList;
import org.civilian.request.Session;
import org.civilian.util.Check;
/**
* TestResponse is a {@link Response} implementation to be used in a test environment.
*/
public class TestResponse extends AbstractResponse
{
public TestResponse(Request request)
{
super(request);
}
public TestResponse(TestRequest request, TestResponse response)
{
this(request);
headers_ = response.headers_;
bufferSize_ = response.bufferSize_;
}
@Override public boolean isCommitted()
{
return isCommitted_;
}
@Override public void reset()
{
checkNotCommitted();
statusCode_ = Status.OK;
headers_.clear();
}
@Override public void addCookie(Cookie cookie)
{
getCookies().add(Check.notNull(cookie, "cookie"));
}
public CookieList getCookies()
{
if (cookies_ == null)
cookies_ = new CookieList();
return cookies_;
}
/**
* Appends the session id to the url, if a session id was set.
*/
@Override public String addSessionId(String url)
{
Session session = getRequest().getSession(false);
return session != null ? url + ";session=" + session.getId() : url;
}
@Override protected void sendRedirectImpl(String url) throws IOException
{
resetBuffer();
getHeaders().set("Location", url);
setStatus(Status.SC302_FOUND);
flushBuffer();
}
@Override public int getStatus()
{
return statusCode_;
}
@Override public void setStatus(int statusCode)
{
statusCode_ = statusCode;
}
//-----------------------------------
// response content
//-----------------------------------
@Override public void setContentType(ContentType contentType)
{
contentType_ = contentType;
}
@Override public ContentType getContentType()
{
return contentType_;
}
@SuppressWarnings("resource")
@Override protected OutputStream getContentStreamImpl() throws IOException
{
OutputStream out = outputStream_ = new ResponseStream();
if (bufferSize_ > 0)
out = bufferedStream_ = new BufferedStream(out, bufferSize_);
return out;
}
@Override protected Writer getContentWriterImpl() throws IOException
{
return null;
}
@Override protected void setContentEncodingImpl(String encoding)
{
// encoding already stored in AbstractResponse
}
@Override public void setContentLength(long length)
{
contentLength_ = length;
getHeaders().set("Content-Length", length < 0 ? null : String.valueOf(length));
}
/**
* Returns the content-length.
*/
public long getContentLength()
{
return contentLength_;
}
/**
* Returns the byte currently residing in the buffer
* converted to a string. This does not use any encoding,
* hence it only makes sense if the buffer contains 7-bit data.
*/
public String getBufferText() throws IOException
{
return new String(getBufferBytes());
}
/**
* Returns the byte currently residing in the buffer.
*/
public byte[] getBufferBytes() throws IOException
{
return bufferedStream_ != null ? bufferedStream_.getBufferBytes() : new byte[0];
}
/**
* Returns the current response content as byte array.
*/
public byte[] getContentBytes(boolean flushBuffer) throws IOException
{
if (flushBuffer)
flushBuffer();
return outputStream_ != null ? outputStream_.toByteArray() : new byte[0];
}
/**
* Returns the current response content as text string.
*/
public String getContentText(boolean flushBuffer) throws IOException
{
if (flushBuffer)
flushBuffer();
if (outputStream_ != null)
{
String encoding = getContentEncoding();
if (encoding == null)
encoding = getApplication().getEncoding();
// does not help to call setContentEncoding() since
// it is ignored since we already obtaine an outputstream or writer
return outputStream_.toString(encoding);
}
else
return "";
}
//----------------------------
// response buffer
//----------------------------
@Override protected void resetBufferImpl()
{
checkNotCommitted();
if (bufferedStream_ != null)
bufferedStream_.reset();
if (outputStream_ != null)
outputStream_.reset();
}
@Override protected void flushBuffer(Flushable flushable) throws IOException
{
isCommitted_ = true;
if (flushable != null)
flushable.flush();
}
/**
* Clears the committed flag and resets the buffer.
*/
public void clearCommitted()
{
isCommitted_ = false;
resetBuffer();
}
/**
* Set the response into an initial state.
* A cleared response can be reused again.
*/
@Override public void clear()
{
clearCommitted();
super.clear();
reset();
outputStream_ = null;
bufferedStream_ = null;
}
@Override public void setBufferSize(int size)
{
if (getContentAccess() != ContentAccess.NONE)
throw new IllegalStateException("content already written");
bufferSize_ = Math.max(0, size);
}
@Override public int getBufferSize()
{
return bufferSize_;
}
@Override public ParamList getHeaders()
{
return headers_;
}
/**
* Returns null.
*/
@Override public <T> T unwrap(Class<T> implClass)
{
return null;
}
private static class BufferedStream extends BufferedOutputStream
{
public BufferedStream(OutputStream out, int size)
{
super(out, size);
}
public byte[] getBufferBytes()
{
byte[] bytes = new byte[count];
System.arraycopy(buf, 0, bytes, 0, count);
return bytes;
}
public void reset()
{
count = 0;
}
}
private class ResponseStream extends ByteArrayOutputStream
{
@Override public void flush() throws IOException
{
super.flush();
isCommitted_ = true;
}
}
private int statusCode_ = Status.OK;
private boolean isCommitted_;
private ParamList headers_ = new ParamList(true);
private ContentType contentType_;
private long contentLength_ = -1;
private int bufferSize_ = 4096;
private BufferedStream bufferedStream_;
private ResponseStream outputStream_;
private CookieList cookies_;
}