org.LexGrid.LexBIG.caCore.web.util.LexEVSHTTPQuery.java Source code

Java tutorial

Introduction

Here is the source code for org.LexGrid.LexBIG.caCore.web.util.LexEVSHTTPQuery.java

Source

/*
* Copyright: (c) Mayo Foundation for Medical Education and
* Research (MFMER). All rights reserved. MAYO, MAYO CLINIC, and the
* triple-shield Mayo logo are trademarks and service marks of MFMER.
*
* Distributed under the OSI-approved BSD 3-Clause License.
* See http://ncip.github.com/lexevs-remote/LICENSE.txt for details.
*/
package org.LexGrid.LexBIG.caCore.web.util;

import gov.nih.nci.system.util.SystemConstant;

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.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.LexGrid.LexBIG.caCore.dao.orm.selectionStrategy.exceptions.SelectionStrategyException;
import org.LexGrid.LexBIG.caCore.web.exceptions.WebQueryException;
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 LexEVSHTTPQuery extends HttpServlet {

    private static final long serialVersionUID = 1L;

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

    private String cacoreStyleSheet;
    private String jsonStyleSheet;

    private int pageSize = 1000; //default

    ServletContext context;

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

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

        cacoreStyleSheet = systemProperties.getProperty("resultOutputFormatter");
        jsonStyleSheet = systemProperties.getProperty("jsonOutputFormatter");

        log.debug("cacoreStylesheet: " + cacoreStyleSheet);

        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 {
        int localPageSize = this.pageSize;

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

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

        LexEVSHTTPUtils httpUtils = new LexEVSHTTPUtils(context);

        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);

            httpUtils.setServletName(request.getRequestURL().toString());

            if (httpUtils.getPageSize() != null) {
                localPageSize = Integer.parseInt(httpUtils.getPageSize());
            } else {
                httpUtils.setPageSize(localPageSize);
            }

            resultSet = httpUtils.getResultSet();

            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);

                    }
                } else {
                    response.setContentType("text/html");
                    if (httpUtils.getTargetPackageName() != null) {
                        printDocument(domDoc, cacoreStyleSheet, out);
                    }
                }

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

            log.error("Exception: ", ex);
            if (ex instanceof SelectionStrategyException
                    || (ex.getCause() != null && ex.getCause() instanceof SelectionStrategyException)) {

                response.sendError(HttpServletResponse.SC_NOT_FOUND,
                        "The requested Coding Scheme is not available. \n\n" + ex.getMessage());
            } else if (ex instanceof WebQueryException
                    || (ex.getCause() != null && ex.getCause() instanceof WebQueryException)) {

                response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
            } else {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 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 void transform(Document xmlDoc, InputStream styleIn, OutputStream out) throws Exception {

        if (styleIn == null)
            throw new ServletException("No stylesheet configued");

        JDOMSource source = new JDOMSource(xmlDoc);
        StreamResult result = new StreamResult(out);

        try {
            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());
        }
    }

    /**
     * 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) throws Exception {

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

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

    /**
     * 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();
        msg = org.apache.commons.lang.StringEscapeUtils.escapeHtml(msg);
        Throwable tempEx = ex.getCause();
        while (tempEx != null) {
            msg += "<br><br>Caused by: " + tempEx.getMessage();
            tempEx = tempEx.getCause();
        }

        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 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 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 WebQueryException(
                        "Invalid format: '[' parenthesis does not match number of ']' parenthesis");
            }
        } else {
            Encode encoder = new Encode("ESCAPE_XML");
            throw new WebQueryException("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;

    }

}