package org.opennaas.itests.helpers.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;
import org.eclipse.jetty.http.HttpStatus;
import org.opennaas.core.resources.helpers.XmlHelper;
import org.xml.sax.SAXException;
/**
* Servlet for the HTTP Server.
*
* The HTTP servlet is the one containing the list of {@link HTTPServerBehaviour}, which define the answers of the server to specific requests.
* Request sent by the user that are not defined in the list of behaviors are answered with a {@link HttpServletResponse}
*
* In the other hand, if the user's request matches a desired behavior, the associated request is sent to the user, which could be either a sucessfull
* or error answer. If the behavior was consumable, it's removed from the list whenever a request matches it.
*
*
* @author Adrian Rosello Rey (i2CAT)
*
*/
public class HTTPServerServlet extends HttpServlet {
private static final long serialVersionUID = -7639723130739143382L;
private List<HTTPServerBehaviour> desiredBehaviour;
private String reqContentType;
private String reqBody;
private String reqURL;
private String reqMethod; ;
public HTTPServerServlet(List<HTTPServerBehaviour> servletBehaviours) {
this.desiredBehaviour = servletBehaviours;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
createResponse(request, response);
}
@Override
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
createResponse(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
createResponse(request, response);
}
@Override
protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
createResponse(request, response);
}
private void createResponse(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
this.reqContentType = request.getContentType();
this.reqURL = request.getRequestURI();
this.reqMethod = request.getMethod();
this.reqBody = getBodyMessage(request);
HTTPServerBehaviour behavior = getDesiredBehavior();
if (behavior == null)
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
else {
HTTPResponse desiredResponse = behavior.getResponse();
if (behavior.isConsumable())
desiredBehaviour.remove(behavior);
int status = desiredResponse.getStatus();
if (HttpStatus.isServerError(status) || HttpStatus.isClientError(status))
response.sendError(status);
else {
response.getWriter().println(desiredResponse.getBodyMessage());
response.setContentType(desiredResponse.getContentType());
response.setStatus(desiredResponse.getStatus());
}
}
}
private HTTPServerBehaviour getDesiredBehavior() throws IOException, ServletException
{
try {
Iterator<HTTPServerBehaviour> iterator = desiredBehaviour.iterator();
while (iterator.hasNext()) {
HTTPServerBehaviour behaviour = iterator.next();
HTTPRequest possibleReq = behaviour.getRequest();
if (requestMatches(possibleReq)) {
return behaviour;
}
}
return null;
} catch (SAXException e) {
throw new ServletException(e);
} catch (TransformerException e) {
throw new ServletException(e);
} catch (ParserConfigurationException e) {
throw new ServletException(e);
}
}
private boolean requestMatches(HTTPRequest possibleReq) throws IOException, SAXException, TransformerException,
ParserConfigurationException {
if (!possibleReq.getMethod().equals(this.reqMethod))
return false;
if (!possibleReq.getRequestURL().equals(this.reqURL))
return false;
if (!bodyMatches(possibleReq.getBodyMessage(), possibleReq.getContentType(),
possibleReq.getOmittedFields()))
return false;
return true;
}
private boolean bodyMatches(String possibleReqBody, String possibleReqContentType,
List<String> ommitedFields)
throws JsonProcessingException, IOException, SAXException, TransformerException, ParserConfigurationException {
if (!StringUtils.equals(this.reqContentType, possibleReqContentType))
return false;
if (StringUtils.isBlank(this.reqBody) && StringUtils.isBlank(possibleReqBody))
return true;
if ((StringUtils.isBlank(this.reqBody) && StringUtils.isNotBlank(possibleReqBody)) || ((StringUtils.isNotBlank(this.reqBody) && StringUtils
.isBlank(possibleReqBody))))
return false;
if (this.reqContentType.contains(MediaType.APPLICATION_XML) || this.reqContentType.contains(MediaType.TEXT_XML))
return compareXml(this.reqBody, possibleReqBody);
if (this.reqContentType.contains(MediaType.APPLICATION_JSON))
return compareJson(this.reqBody, possibleReqBody, ommitedFields);
return true;
}
private boolean compareJson(String reqBody, String possibleReqBody, List<String> ommitedFields) throws JsonProcessingException, IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode tree1 = mapper.readTree(reqBody);
JsonNode tree2 = mapper.readTree(possibleReqBody);
for (String field : ommitedFields) {
((ObjectNode) tree1).remove(field);
((ObjectNode) tree2).remove(field);
}
return tree1.equals(tree2);
}
private boolean compareXml(String reqBody, String possibleReqBody) throws SAXException, IOException, TransformerException,
ParserConfigurationException {
String formattedBody = XmlHelper.formatXML(reqBody);
String formattedBody2 = XmlHelper.formatXML(possibleReqBody);
return (formattedBody.equals(formattedBody2));
}
private String getBodyMessage(HttpServletRequest request) throws IOException {
StringBuffer jb = new StringBuffer();
String line = null;
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null)
jb.append(line);
return jb.toString();
}
}