org.n52.ses.common.environment.SESMiniServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.ses.common.environment.SESMiniServlet.java

Source

/**
 * Copyright (C) 2008 - 2014 52North Initiative for Geospatial Open Source
 * Software GmbH
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 *
 * If the program is linked with libraries which are licensed under one of
 * the following licenses, the combination of the program with the linked
 * library is not considered a "derivative work" of the program:
 *
 *     - Apache License, version 2.0
 *     - Apache Software License, version 1.0
 *     - GNU Lesser General Public License, version 3
 *     - Mozilla Public License, versions 1.0, 1.1 and 2.0
 *     - Common Development and Distribution License (CDDL), version 1.0
 *
 * Therefore the distribution of the program linked with libraries licensed
 * under the aforementioned licenses, is permitted by the copyright holders
 * if the distribution is compliant with both the GNU General Public
 * icense version 2 and the aforementioned licenses.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 */
package org.n52.ses.common.environment;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.muse.core.platform.mini.MiniIsolationLayer;
import org.apache.muse.core.platform.mini.MiniServlet;
import org.apache.muse.util.xml.XmlUtils;
import org.apache.muse.ws.addressing.soap.SoapConstants;
import org.apache.muse.ws.addressing.soap.SoapFault;
import org.apache.muse.ws.addressing.soap.SoapUtils;
import org.n52.ses.api.ISESFilePersistence;
import org.n52.ses.common.environment.handler.GetRequestHandler;
import org.n52.ses.common.environment.handler.GetCapabilitiesHandler;
import org.n52.ses.common.environment.handler.WSDLProvisionHandler;
import org.n52.ses.common.environment.handler.XSDProvisionHandler;
import org.n52.ses.requestlogger.RequestLoggerWrapper;
import org.n52.ses.startupinit.StartupInitServlet;
import org.n52.ses.util.common.ConfigurationRegistry;
import org.n52.ses.wsbr.RegisterPublisher;
import org.n52.ses.wsn.SESNotificationProducer;
import org.n52.ses.wsn.SESSubscriptionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * Extended Servlet with support for shutdown and wsdl provision.
 * 
 * @author Matthes Rieke
 *
 */
public class SESMiniServlet extends MiniServlet {

    private static final Logger logger = LoggerFactory.getLogger(SESMiniServlet.class);
    private static final long serialVersionUID = 1L;
    private String landingPage;
    private MiniIsolationLayer sesIsolationLayer;
    private List<GetRequestHandler> getRequestHandlers = new ArrayList<GetRequestHandler>();
    private static int minimumContentLengthForGzip = 500000;
    private static RequestLoggerWrapper loggerInst;
    private static final AtomicBoolean firstResponsePrint = new AtomicBoolean(true);

    public SESMiniServlet() {
        logger.info(readFileContents("/ses_version_info.txt"));
        this.getRequestHandlers.add(new GetCapabilitiesHandler());
        this.getRequestHandlers.add(new WSDLProvisionHandler());
        this.getRequestHandlers.add(new XSDProvisionHandler());
    }

    private String readFileContents(String string) {
        InputStream is = getClass().getResourceAsStream(string);

        if (is != null) {
            Scanner sc = new Scanner(is);
            StringBuilder sb = new StringBuilder();
            while (sc.hasNext()) {
                sb.append(sc.nextLine());
                sb.append(System.getProperty("line.separator"));
            }
            sb.deleteCharAt(sb.length() - 1);
            sc.close();
            return sb.toString();
        }
        return null;
    }

    @Override
    public void destroy() {
        if (ConfigurationRegistry.getInstance() != null) {
            ConfigurationRegistry.getInstance().shutdown();
        }
        super.destroy();
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        synchronized (SESMiniServlet.class) {
            if (this.sesIsolationLayer == null) {
                this.sesIsolationLayer = createIsolationLayer(request, getServletContext());
            }
        }

        InputStream input = request.getInputStream();
        Document soapRequest = null;

        long time = System.currentTimeMillis();

        try {
            soapRequest = XmlUtils.createDocument(input);
        }

        catch (Exception error) {
            logger.warn(error.getMessage(), error);
            SoapFault fault = SoapUtils.convertToFault(error);
            response.setContentType("application/soap+xml; charset=utf-8");
            printResponse(request, response, createSoapFaultEnvelope(fault));
            return;
        }

        handleSoapRequest(request, response, soapRequest);

        if (RequestLoggerWrapper.isActive()) {
            if (loggerInst == null) {
                loggerInst = RequestLoggerWrapper.getInstance();
            }
            if (loggerInst != null)
                loggerInst.logRequest(time, soapRequest);
        }
    }

    private String createSoapFaultEnvelope(SoapFault fault) {
        Document response = XmlUtils.createDocument();

        Element soap = XmlUtils.createElement(response, SoapConstants.ENVELOPE_QNAME);
        response.appendChild(soap);

        Element body = XmlUtils.createElement(response, SoapConstants.BODY_QNAME);
        soap.appendChild(body);

        Element result = (Element) response.importNode(fault.toXML(), true);
        body.appendChild(result);

        return XmlUtils.toString(response);
    }

    private void handleSoapRequest(HttpServletRequest request, HttpServletResponse response, Document soapRequest)
            throws IOException {
        Document soapResponse;
        try {
            soapResponse = this.sesIsolationLayer.handleRequest(soapRequest);
        } catch (RuntimeException e) {
            throw new IOException(e);
        }

        /*
         * is null? return a http response code.
         * change made by Matthes Rieke <m.rieke@uni-muenster.de>
         */
        if (soapResponse == null) {
            response.setStatus(HttpServletResponse.SC_NO_CONTENT);
        } else {
            //TODO check support of ' ; charset=utf-8'
            response.setContentType("application/soap+xml; charset=utf-8");
            printResponse(request, response, XmlUtils.toString(soapResponse));
        }
    }

    private boolean clientSupportsGzip(HttpServletRequest request) {
        String header = request.getHeader("Accept-Encoding");
        if (header != null && !header.isEmpty()) {
            String[] split = header.split(",");
            for (String string : split) {
                if (string.equalsIgnoreCase("gzip")) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ConfigurationRegistry conf = ConfigurationRegistry.getInstance();

        for (GetRequestHandler handler : this.getRequestHandlers) {
            if (handler.canHandle(req)) {
                try {
                    printResponse(req, resp, handler.handleRequest(req, resp, conf, this.sesIsolationLayer));
                } catch (Exception e) {
                    throw new ServletException(e);
                }
                return;
            }
        }

        provideLandingPage(req, resp, conf);
    }

    private void provideLandingPage(HttpServletRequest req, HttpServletResponse resp, ConfigurationRegistry conf)
            throws IOException, UnsupportedEncodingException {
        /*
         * return landing page
         */
        if (this.landingPage != null) {
            resp.setContentType("text/html");
            synchronized (this) {
                printResponse(req, resp, this.landingPage);
            }

            return;
        }

        InputStreamReader isr = new InputStreamReader(getClass().getResourceAsStream("/landing_page.html"));
        BufferedReader br = new BufferedReader(isr);
        StringBuilder sb = new StringBuilder();

        while (br.ready()) {
            sb.append(br.readLine());
        }
        String html = sb.toString();

        String reqUrl = URLDecoder.decode(req.getRequestURL().toString(),
                (req.getCharacterEncoding() == null ? Charset.defaultCharset().name()
                        : req.getCharacterEncoding()));
        html = html.replace("[SES_URL]",
                reqUrl.substring(0, reqUrl.indexOf(req.getContextPath())) + req.getContextPath());

        /*
         * check if we are init yet
         */
        String sesPortTypeUrl, subMgrUrl, prmUrl = "";
        if (conf != null) {
            String defaulturi = conf.getEnvironment().getDefaultURI().substring(0,
                    conf.getEnvironment().getDefaultURI().lastIndexOf("/services"));
            sesPortTypeUrl = defaulturi + "/services/" + SESNotificationProducer.CONTEXT_PATH;
            subMgrUrl = defaulturi + "/services/" + SESSubscriptionManager.CONTEXT_PATH;
            prmUrl = defaulturi + "/services/" + RegisterPublisher.RESOURCE_TYPE;

            conf.setSubscriptionManagerWsdl(subMgrUrl + "?wsdl");

            html = html.replace("<p id=\"ses-status\"><p>",
                    "<p style=\"color:#0f0\">The service is active and available.</p>");

            html = html.replace("[GET_CAPS]",
                    StringEscapeUtils.escapeHtml4(StartupInitServlet.getGetCapabilitiesRequest(sesPortTypeUrl)));
            /*
             * replace the url
             */
            synchronized (this) {
                if (this.landingPage == null) {
                    this.landingPage = html.replace("[SES_PORT_TYPE_URL]", sesPortTypeUrl);
                    this.landingPage = this.landingPage.replace("[SUB_MGR_URL]", subMgrUrl);
                    this.landingPage = this.landingPage.replace("[PRM_URL]", prmUrl);

                    resp.setContentType("text/html");
                    printResponse(req, resp, this.landingPage);
                }

            }

        } else {
            /*
             * we do not have the config, warn the user
             */
            html = html.replace("<p id=\"ses-status\"><p>",
                    "<p style=\"color:#f00\">The service is currently not available due to unfinished or failed initialization.</p>");

            resp.setContentType("text/html");
            printResponse(req, resp, html);
        }
    }

    private void printResponse(HttpServletRequest request, HttpServletResponse response, String string)
            throws IOException {
        int contentLength = string.getBytes("UTF-8").length;

        if (firstResponsePrint.getAndSet(false)) {
            ConfigurationRegistry conf = ConfigurationRegistry.getInstance();
            if (conf == null) {
                firstResponsePrint.getAndSet(true);
            } else {
                minimumContentLengthForGzip = Integer
                        .parseInt(conf.getPropertyForKey(ConfigurationRegistry.MINIMUM_GZIP_SIZE));
            }
        }

        // compressed response
        if (contentLength > minimumContentLengthForGzip && clientSupportsGzip(request)) {
            response.addHeader("Content-Encoding", "gzip");
            GZIPOutputStream gzip = new GZIPOutputStream(response.getOutputStream(), contentLength);
            String type = response.getContentType();
            if (!type.contains("charset")) {
                response.setContentType(type + "; charset=utf-8");
            }
            gzip.write(string.getBytes(Charset.forName("UTF-8")));
            gzip.flush();
            gzip.finish();
        }
        // uncompressed response
        else {
            response.setContentLength(contentLength);
            response.setCharacterEncoding("UTF-8");
            PrintWriter writer = response.getWriter();
            writer.write(string);
            writer.flush();
        }

    }

    @Override
    protected MiniIsolationLayer createIsolationLayer(HttpServletRequest request, ServletContext context) {
        MiniIsolationLayer isolationLayer = new SESMiniIsolationLayer(request, context);
        isolationLayer.initialize();

        ConfigurationRegistry.getInstance()
                .setFilePersistence((ISESFilePersistence) isolationLayer.getRouter().getPersistence());

        return isolationLayer;
    }

}