gov.nih.nci.system.web.HTTPQuery.java Source code

Java tutorial

Introduction

Here is the source code for gov.nih.nci.system.web.HTTPQuery.java

Source

/*L
 *  Copyright Ekagra Software Technologies Ltd.
 *  Copyright SAIC, SAIC-Frederick
 *
 *  Distributed under the OSI-approved BSD 3-Clause License.
 *  See http://ncip.github.com/cacore-sdk/LICENSE.txt for details.
 */

package gov.nih.nci.system.web;

import gov.nih.nci.system.applicationservice.ApplicationService;
import gov.nih.nci.system.dao.orm.HibernateConfigurationHolder;
import gov.nih.nci.system.util.ClassCache;
import gov.nih.nci.system.util.SystemConstant;
import gov.nih.nci.system.web.util.HTTPUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.Properties;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;

import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.output.XMLOutputter;
import org.jdom.transform.JDOMResult;
import org.jdom.transform.JDOMSource;
import org.mmbase.util.Encode;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * The HTTPQuery servlet interpretes a query request and makes appropriate calls to the Application Service interface.
 * The results are sent back to the user as an XML or HTML document based on the type of request made.
 * XQuery like syntax is used to generate the query.
 *
 * Syntax:
 * http://server:port/servlet/queryType?query=targetClassName&criteriaClassName[@attribute=value][association[@attribute=value]]
 * Please refer to the cacore documentation for more information on generating a query request.
 */
public class HTTPQuery extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private static Logger log = Logger.getLogger(HTTPQuery.class.getName());

    private String cacoreStyleSheet;
    private String jsonStyleSheet;

    private int pageSize = 1000; //default

    WebApplicationContext ctx;

    /**
     * Initialize the servlet
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        ServletContext context = config.getServletContext();

        ctx = WebApplicationContextUtils.getWebApplicationContext(context);
        Properties systemProperties = (Properties) ctx.getBean("WebSystemProperties");

        cacoreStyleSheet = systemProperties.getProperty("resultOutputFormatter");
        jsonStyleSheet = systemProperties.getProperty("jsonOutputFormatter");
        log.debug("cacoreStylesheet: " + cacoreStyleSheet);
        log.debug("jsonStyleSheet: " + jsonStyleSheet);

        try {
            String pageCount = systemProperties.getProperty("rowCounter");
            log.debug("rowCounter: " + pageCount);
            if (pageCount != null) {
                pageSize = Integer.parseInt(pageCount);
            }
        } catch (Exception ex) {
            log.error("Exception: ", ex);
        }
    }

    /**
     * Handls Post requests
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    /**
     * Unload servlet
     */
    public void destroy() {
        super.destroy();
    }

    /**
     * Handles Get requests
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        ServletOutputStream out = response.getOutputStream();
        out = response.getOutputStream();

        Object[] resultSet = null;
        int pageNumber = 1;

        ApplicationService applicationService = (ApplicationService) ctx.getBean("ApplicationServiceImpl");
        ClassCache classCache = (ClassCache) ctx.getBean("ClassCache");
        HibernateConfigurationHolder configurationHolder = (HibernateConfigurationHolder) ctx
                .getBean("HibernateConfigHolder");
        HTTPUtils httpUtils = new HTTPUtils(applicationService, classCache, pageSize, configurationHolder);
        String queryType = httpUtils.getQueryType(request.getRequestURL().toString());

        String query = null;

        try {
            if (URLDecoder.decode(request.getQueryString(), "ISO-8859-1") != null) {
                query = URLDecoder.decode(request.getQueryString(), "ISO-8859-1");
            } else {
                throw new Exception("Query not defined" + getQuerySyntax());
            }
            if (query.indexOf("&username") > 0)
                query = query.substring(0, query.indexOf("&username"));

            validateQuery(query);
            httpUtils.setQueryArguments(query);

            if (httpUtils.getPageNumber() != null) {
                pageNumber = Integer.parseInt(httpUtils.getPageNumber());
            }
            httpUtils.setServletName(request.getRequestURL().toString());

            if (httpUtils.getPageSize() != null) {
                //FIX for pagesize being reset by the end user
                //pageSize = Integer.parseInt(httpUtils.getPageSize());
            } else {
                httpUtils.setPageSize(pageSize);
            }

            try {
                resultSet = httpUtils.getResultSet();
            } catch (Exception ex) {
                log.error("Get ResultSet Exception: " + ex.getMessage());
                throw ex;
            }
            executeFormatOutput(response, out, resultSet, pageNumber, httpUtils, queryType);
        } catch (Exception ex) {
            log.error("Exception: ", ex);

            if (queryType.endsWith("XML")) {
                response.setContentType("text/xml");

                out.println(getXMLErrorMsg(ex, query));
            } else {
                response.setContentType("text/html");
                out.println(getHTMLErrorMsg(ex));
            }
            // Need to add JSON error output???
        }

    }

    private void executeFormatOutput(HttpServletResponse response, ServletOutputStream out, Object[] resultSet,
            int pageNumber, HTTPUtils httpUtils, String queryType) throws Exception {
        try {

            XMLOutputter xout = new XMLOutputter();
            org.jdom.Document domDoc = httpUtils.getXMLDocument(resultSet, pageNumber);

            if (queryType.endsWith("XML")) {
                response.setContentType("text/xml");
                xout.output(domDoc, out);
            } else if (queryType.endsWith("JSON")) {
                response.setContentType("application/x-javascript");
                if (httpUtils.getTargetPackageName() != null) {
                    printDocument(domDoc, jsonStyleSheet, out, httpUtils);
                }
            } else {
                response.setContentType("text/html");
                if (httpUtils.getTargetPackageName() != null) {
                    printDocument(domDoc, cacoreStyleSheet, out, httpUtils);
                }
            }

        } catch (Exception ex) {
            log.error("Print Results Exception: " + ex.getMessage());
            throw ex;
        }
    }

    /**
     * Generates an HTML Document for a given XML document with the given stylesheet specification
     * @param doc Specifies the XML document
     * @param styleSheet Specifies the stylesheet
     * @return
     * @throws Exception
     */
    public Document getHTMLDocument(Document doc, String styleSheet) throws Exception {
        Document htmlDoc = null;

        try {
            InputStream styleIn = Thread.currentThread().getContextClassLoader().getResourceAsStream(styleSheet);
            if (styleIn != null) {
                htmlDoc = XSLTTransformer(doc, styleIn);
            }

        } catch (Exception ex) {
            log.error(ex.getMessage());
            throw new ServletException(ex.getMessage());
        }
        return htmlDoc;
    }

    /**
     * Generates an HTML Error message based upon a given Exception
     * @param    Exception The exception that should be used to generate an HTML error message
     * @return   A string-based HTML error message containing the Exception message.
     */
    private String getXMLErrorMsg(Exception ex, String query) {

        StringBuilder sb = new StringBuilder();

        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
                .append("<xlink:httpQuery xmlns:xlink=\"http://www.w3.org/1999/xlink\">").append("<queryRequest>")
                .append("<query>").append("<queryString>" + query + "</queryString>").append("<class></class>")
                .append("</query>").append("<criteria></criteria>").append("</queryRequest>")
                .append("<queryResponse>");

        String msg = ex.getMessage();
        msg = org.apache.commons.lang.StringEscapeUtils.escapeXml(msg);
        Throwable tempEx = ex.getCause();
        while (tempEx != null) {
            msg += "\n\nCaused by: " + tempEx.getMessage();
            tempEx = tempEx.getCause();
        }

        sb.append(msg);

        sb.append("<error>" + msg + "</error>").append("</queryReponse>").append("</xlink:httpQuery>");

        return sb.toString();
    }

    /**
     * Generates an HTML Error message based upon a given Exception
     * @param    Exception The exception that should be used to generate an HTML error message
     * @return   A string-based HTML error message containing the Exception message.
     */
    private String getHTMLErrorMsg(Exception ex) {

        StringBuilder sb = new StringBuilder();

        sb.append("<html>\n").append("<head>\n").append("<title>caCORE HTTP Servlet Error</title>\n")
                .append("</head>\n").append("<body>\n")
                .append("<table height=\"100%\" width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" >\n")
                .append("<tr valign=\"top\" align=\"left\">\n").append("<td valign=\"top\" align=\"left\">\n")

                .append("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" >\n")
                .append("<tr valign=\"top\" align=\"left\">\n").append("<td valign=\"top\" align=\"left\">\n")
                .append("<tr>\n").append("<td valign=\"top\" align=\"left\">\n")
                .append("<b><font size=6>caCORE HTTP Servlet Error:</font></b>\n").append("</td>\n")
                .append("</tr>\n").append("<tr>\n").append("<td valign=\"top\" align=\"left\">\n")
                .append("<b><hr></b>\n").append("</td>\n").append("</tr>\n").append("<tr>\n")
                .append("<td valign=\"top\" align=\"left\">\n").append("<pre class=\"autoOverflow\">\n")
                .append("<font size=4 color=red><b><br><br>\n");

        String msg = ex.getMessage();
        Throwable tempEx = ex.getCause();
        while (tempEx != null) {
            msg += "<br><br>Caused by: " + tempEx.getMessage();
            tempEx = tempEx.getCause();
        }

        msg = org.apache.commons.lang.StringEscapeUtils.escapeHtml(msg);
        sb.append(msg);

        sb.append("</b></font>\n").append("</pre>\n").append("</td>\n").append("</tr>\n").append("</td>\n")
                .append("</tr>\n").append("</table>\n");

        return sb.toString();
    }

    /**
     * Generates an HTML Document for a given XML document with the given stylesheet specification
     * @param doc Specifies the XML document
     * @param styleSheet Specifies the stylesheet
     * @return
     * @throws Exception
     */
    public void printDocument(Document doc, String styleSheet, OutputStream out, HTTPUtils httpUtils)
            throws Exception {
        try {
            InputStream styleIn = Thread.currentThread().getContextClassLoader().getResourceAsStream(styleSheet);
            if (styleIn != null) {
                httpUtils.transform(doc, styleIn, out);
            }

        } catch (Exception ex) {
            log.error(ex.getMessage());
            throw new ServletException(ex.getMessage());
        }
    }

    /**
     * Generates an XML or HTML document based on a given stylesheet
     * @param xmlDoc Specifies the xml document
     * @param styleIn specifies the stylesheet
     * @return
     * @throws Exception
     */

    public Document XSLTTransformer(Document xmlDoc, InputStream styleIn) throws Exception {
        JDOMSource source = new JDOMSource(xmlDoc);
        JDOMResult result = new JDOMResult();
        try {
            if (styleIn != null) {
                TransformerFactory tFactory = TransformerFactory.newInstance();
                Templates stylesheet = tFactory.newTemplates(new StreamSource(styleIn));
                Transformer processor = stylesheet.newTransformer();
                processor.transform(source, result);
            }

        } catch (Exception ex) {
            log.error(ex.getMessage());
            throw new Exception("XSLTTransformer Exception: " + ex.getMessage());
        }
        return result.getDocument();
    }

    /**
     * This method returns true if the query syntax is valid
     * @param query Specifies the http query
     * @return return
     */
    private boolean validateQuery(String query) throws Exception {
        boolean valid = true;
        try {
            if (query.indexOf("query") < 0) {
                valid = false;
            } else if (query.endsWith("query=")) {
                valid = false;
            } else if (query.endsWith("query")) {
                valid = false;
            } else if (query.endsWith("&") || query.endsWith("[")) {
                valid = false;
            }

        } catch (Exception ex) {
            valid = false;
        }
        if (valid) {
            int startCounter = 0;
            int endCounter = 0;
            for (int i = 0; i < query.length(); i++) {
                if (query.charAt(i) == SystemConstant.LEFT_BRACKET) {
                    startCounter++;
                } else if (query.charAt(i) == SystemConstant.RIGHT_BRACKET) {
                    endCounter++;
                }
            }
            if (startCounter != endCounter) {
                throw new Exception("Invalid format: '[' parenthesis does not match number of ']' parenthesis");
            }
        } else {
            Encode encoder = new Encode("ESCAPE_XML");
            throw new Exception("Invalid Syntax: " + encoder.encode(query) + getQuerySyntax());
        }
        return valid;
    }

    /**
     * Returns the query syntax
     * @return
     */
    private String getQuerySyntax() {
        String syntax = "<br><br><font color=black size=4><B>Syntax: </B><br>"
                + "<font color=purple>query=</font>TargetClassName" + "<font color=purple>&</font>CriteriaClassName"
                + "<font color=purple>[@</font>attribute" + "<font color=purple>=</font>value"
                + "<font color=purple>][</font>association" + "<font color=purple>[@</font>attribute"
                + "<font color=purple>=</font>value" + "<font color=purple>]]<font color=purple></font>";
        return syntax;

    }
}