/**
*
*/
package org.jboss.test.faces.staging;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jboss.test.faces.TestException;
/**
* This class represent single connection ( request ) to the virtual server. These instance should not be created directly, but by the {@link StagingServer#getConnection(URL)}.
* method only.
* Since instance have been created, additional request parameters and headers can be set.
* @author asmirnov
*
*/
public class StagingConnection extends HttpConnection {
private static final Logger log = ServerLogger.SERVER.getLogger();
private final StagingServer server;
private final URL url;
private final ConnectionRequest request;
private final ConnectionResponse response;
private final RequestChain servlet;
private static final Cookie[] COOKIE = new Cookie[] {};
private List<Cookie> cookies = new ArrayList<Cookie>();
private final String pathInfo;
private final String servletPath;
private boolean finished = false;
private boolean started = false;
private final HttpServletRequest requestProxy;
private final HttpServletResponse responseProxy;
/**
* Create connection instance.
* @param localServer virtual server instance.
* @param url request URL.
*/
StagingConnection(StagingServer localServer, URL url) {
this.server = localServer;
this.url = url;
// TODO - context path support.
String path = url.getPath();
servlet = localServer.getServlet(path);
if (null == servlet) {
throw new IllegalArgumentException();
}
this.pathInfo = servlet.getPathInfo(path);
this.servletPath = servlet.getServletPath(path);
this.request = new ConnectionRequest();
this.response = new ConnectionResponse();
this.request.setAttribute("javax.servlet.include.path_info",
this.pathInfo);
this.request.setAttribute("javax.servlet.include.servlet_path",
this.servletPath);
String queryString = url.getQuery();
if (null != queryString) {
parseFormParameters(queryString);
}
// Create proxy objects.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if(null == loader){
loader = this.getClass().getClassLoader();
}
requestProxy = (HttpServletRequest) Proxy.newProxyInstance(loader, new Class[]{HttpServletRequest.class}, server.getInvocationHandler(request));
responseProxy = (HttpServletResponse) Proxy.newProxyInstance(loader, new Class[]{HttpServletResponse.class}, server.getInvocationHandler(response));
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#isFinished()
*/
@Override
public boolean isFinished() {
return finished;
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#isStarted()
*/
@Override
public boolean isStarted() {
return started;
}
// private void checkStarted() {
// if (!isFinished()) {
// throw new TestException("request have not been started");
// }
// }
// private void checkNotStarted() {
// if (isStarted()) {
// throw new TestException("request was started, no parameters changes allowed");
// }
// }
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#execute()
*/
@Override
public void execute() {
if (isStarted() || isFinished()) {
throw new TestException(
"request have already been executed");
}
start();
try {
this.servlet.execute(request, response);
} catch (ServletException e) {
throw new TestException("Error execute request ",e);
} catch (IOException e) {
throw new TestException("IO Error during request execution",e);
} finally {
finish();
}
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#finish()
*/
@Override
public void finish() {
server.requestFinished(request);
finished = true;
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#start()
*/
@Override
public void start() {
log.fine("start " + getRequestMethod() + " request processing for file "
+ url.getFile());
log.fine("request parameters: " + getRequestParameters());
server.requestStarted(request);
started = true;
}
/**
* Get request url.
* @return the url
*/
public URL getUrl() {
return url;
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getContentAsString()
*/
@Override
public String getContentAsString() {
// checkStarted();
String content = response.getWriterContent();
if (null == content) {
byte[] streamContent = response.getStreamContent();
if (null != streamContent) {
String encoding = response.getCharacterEncoding();
if (null != encoding) {
try {
content = new String(streamContent, encoding);
} catch (UnsupportedEncodingException e) {
throw new TestException(e);
}
} else {
content = new String(streamContent);
}
}
}
return content;
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getResponseBody()
*/
@Override
public byte[] getResponseBody() {
// checkStarted();
byte[] content = response.getStreamContent();
if (null == content) {
String writerContent = response.getWriterContent();
if (null != writerContent) {
try {
content = writerContent.getBytes(response
.getCharacterEncoding());
} catch (UnsupportedEncodingException e) {
content = writerContent.getBytes();
}
} else {
content = new byte[0];
}
}
return content;
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getCookies()
*/
private List<Cookie> getCookies() {
return cookies;
}
/**
* request object for the this connection.
* @return the request
*/
@Override
public HttpServletRequest getRequest() {
return requestProxy;
}
/**
* response object for the this connection.
* @return the response
*/
@Override
public HttpServletResponse getResponse() {
return responseProxy;
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getResponseCharacterEncoding()
*/
@Override
public String getResponseCharacterEncoding() {
// checkStarted();
return response.getCharacterEncoding();
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getResponseContentType()
*/
@Override
public String getResponseContentType() {
// checkStarted();
return response.getContentType();
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getResponseStatus()
*/
@Override
public int getResponseStatus() {
// checkStarted();
return response.getStatus();
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getErrorMessage()
*/
@Override
public String getErrorMessage() {
// checkStarted();
return response.getErrorMessage();
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getResponseHeaders()
*/
@Override
public Map<String, String[]> getResponseHeaders() {
// checkStarted();
return response.getHeaders();
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#setRequestCharacterEncoding(java.lang.String)
*/
@Override
public void setRequestCharacterEncoding(String charset) throws UnsupportedEncodingException {
// checkNotStarted();
request.setCharacterEncoding(charset);
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#setRequestBody(java.lang.String)
*/
@Override
public void setRequestBody(String body) {
// checkNotStarted();
request.setRequestBody(body);
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#setRequestContentType(java.lang.String)
*/
@Override
public void setRequestContentType(String contentType) {
// checkNotStarted();
request.setContentType(contentType);
}
/**
* Append additional HTTP request headers.
* @param headers
*/
@Override
public void addRequestHeaders(Map<String, String> headers) {
// checkNotStarted();
request.addHeaders(headers);
}
private class ConnectionRequest extends StagingHttpRequest {
public Cookie[] getCookies() {
return cookies.toArray(COOKIE);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.http.HttpServletRequest#getMethod()
*/
public String getMethod() {
return getRequestMethod().toString();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.http.HttpServletRequest#getServletPath()
*/
public String getServletPath() {
return servletPath;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.http.HttpServletRequest#getPathInfo()
*/
public String getPathInfo() {
return pathInfo;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.http.HttpServletRequest#getQueryString()
*/
public String getQueryString() {
return getRequestQueryString();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.http.HttpServletRequest#getRequestURI()
*/
public String getRequestURI() {
return url.getPath();
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.StagingHttpRequest#getServerName()
*/
@Override
public String getServerName() {
return url.getHost();
}
@Override
public int getLocalPort() {
int port = url.getPort();
if(port < 0){
port = super.getLocalPort();
}
return port;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.ServletRequest#getParameter(java.lang.String)
*/
public String getParameter(String name) {
String[] values = getRequestParameters().get(name);
if (null != values && values.length > 0) {
return values[0];
}
return null;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.ServletRequest#getParameterMap()
*/
@SuppressWarnings("unchecked")
public Map getParameterMap() {
return Collections.unmodifiableMap(getRequestParameters());
}
/*
* (non-Javadoc)
*
* @see javax.servlet.ServletRequest#getParameterNames()
*/
@SuppressWarnings("unchecked")
public Enumeration getParameterNames() {
return Collections.enumeration(getRequestParameters().keySet());
}
/*
* (non-Javadoc)
*
* @see
* javax.servlet.ServletRequest#getParameterValues(java.lang.String)
*/
public String[] getParameterValues(String name) {
return getRequestParameters().get(name);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.http.HttpServletRequest#getSession()
*/
public HttpSession getSession() {
return server.getSession();
}
/*
* (non-Javadoc)
*
* @see javax.servlet.http.HttpServletRequest#getSession(boolean)
*/
public HttpSession getSession(boolean create) {
return server.getSession(create);
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
RequestDispatcher dispatcher = null;
if (!path.startsWith("/")) {
try {
URL absoluteUrl = new URL(url, path);
path = absoluteUrl.getFile();
} catch (MalformedURLException e) {
return null;
}
}
final RequestChain dispatchedServlet = server.getServlet(path);
if (null != dispatchedServlet) {
dispatcher = new RequestDispatcher() {
public void forward(ServletRequest request,
ServletResponse response) throws ServletException,
IOException {
response.reset();
dispatchedServlet.execute(request, response);
}
public void include(ServletRequest request,
ServletResponse response) throws ServletException,
IOException {
dispatchedServlet.execute(request, response);
}
};
}
return dispatcher;
}
@Override
protected void attributeAdded(String name, Object o) {
server.requestAttributeAdded(this, name, o);
}
@Override
protected void attributeRemoved(String name, Object removed) {
server.requestAttributeRemoved(this, name, removed);
}
@Override
protected void attributeReplaced(String name, Object o) {
server.requestAttributeReplaced(this, name, o);
}
}
private class ConnectionResponse extends StagingHttpResponse {
/*
* (non-Javadoc)
*
* @see
* javax.servlet.http.HttpServletResponse#addCookie(javax.servlet.http
* .Cookie )
*/
@Override
public void addCookie(Cookie cookie) {
super.addCookie(cookie);
cookies.add(cookie);
}
}
/* (non-Javadoc)
* @see org.jboss.test.faces.staging.HttpConnection#getResponseContentLength()
*/
@Override
public long getResponseContentLength() {
return response.getContentLength();
}
@Override
protected String getRequestCharacterEncoding() {
return request.getCharacterEncoding();
}
}