nl.b3p.kaartenbalie.service.servlet.CallWMSServlet.java Source code

Java tutorial

Introduction

Here is the source code for nl.b3p.kaartenbalie.service.servlet.CallWMSServlet.java

Source

/*
 * B3P Kaartenbalie is a OGC WMS/WFS proxy that adds functionality
 * for authentication/authorization, pricing and usage reporting.
 *
 * Copyright 2006, 2007, 2008 B3Partners BV
 *
 * This file is part of B3P Kaartenbalie.
 *
 * B3P Kaartenbalie is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * B3P Kaartenbalie 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with B3P Kaartenbalie.  If not, see <http://www.gnu.org/licenses/>.
 */
package nl.b3p.kaartenbalie.service.servlet;

import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import nl.b3p.kaartenbalie.core.server.Organization;
import nl.b3p.kaartenbalie.core.server.User;
import nl.b3p.kaartenbalie.core.server.b3pLayering.ExceptionLayer;
import nl.b3p.kaartenbalie.core.server.monitoring.DataMonitoring;
import nl.b3p.kaartenbalie.core.server.persistence.MyEMFDatabase;
import nl.b3p.kaartenbalie.service.AccessDeniedException;
import nl.b3p.kaartenbalie.service.ProviderException;
import nl.b3p.kaartenbalie.service.requesthandler.*;
import nl.b3p.ogc.utils.KBConfiguration;
import nl.b3p.ogc.utils.OGCConstants;
import nl.b3p.ogc.utils.OGCRequest;
import org.apache.commons.logging.LogFactory;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.*;

public class CallWMSServlet extends GeneralServlet {
    public static final long serialVersionUID = 24362462L;
    public static String CAPABILITIES_DTD = null;
    public static String EXCEPTION_DTD = null;
    public static String DESCRIBELAYER_DTD = null;

    /** Initializes the servlet.
     * Turns the logging of the servlet on.
     *
     * @param config ServletConfig config
     *
     * @throws ServletException
     */
    // <editor-fold defaultstate="" desc="init(ServletConfig config) method.">
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        // Zet de logger
        log = LogFactory.getLog(this.getClass());
        log.debug("Initializing Call WMS Servlet");
    }
    // </editor-fold>

    /** Processes the incoming request and calls the various methods to create the right output stream.
     *
     * @param request servlet request
     * @param response servlet response
     *
     * @throws ServletException
     * @throws IOException
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        long startTime = System.currentTimeMillis();

        StringBuffer baseUrl = createBaseUrl(request, true);
        if (CAPABILITIES_DTD == null) {
            CAPABILITIES_DTD = baseUrl.toString() + "/dtd/capabilities_1_1_1.dtd";
        }
        if (EXCEPTION_DTD == null) {
            EXCEPTION_DTD = baseUrl.toString() + "/dtd/exception_1_1_1.dtd";
        }
        if (DESCRIBELAYER_DTD == null) {
            DESCRIBELAYER_DTD = baseUrl.toString() + "/dtd/WMS_DescribeLayerResponse.dtd";
        }

        DataWrapper data = new DataWrapper(request, response);

        Object identity = null;
        EntityManager em;
        EntityTransaction tx = null;
        try {
            identity = MyEMFDatabase.createEntityManager(MyEMFDatabase.MAIN_EM);
            em = MyEMFDatabase.getEntityManager(MyEMFDatabase.MAIN_EM);
            tx = em.getTransaction();
            tx.begin();

            DataMonitoring rr = new DataMonitoring();
            data.setRequestReporting(rr);

            String serviceName = OGCConstants.WMS_SERVICE_WMS;

            try {
                OGCRequest ogcrequest = calcOGCRequest(request);

                String personalCode = null;
                if (ogcrequest != null)
                    personalCode = ogcrequest.getPersonalCode();

                data.setOgcrequest(ogcrequest);

                String serviceParam = ogcrequest.getParameter(OGCConstants.SERVICE);
                if (serviceParam != null || !"".equals(serviceParam)) {
                    serviceName = serviceParam;
                }

                String iUrl = ogcrequest.getUrl();
                rr.startClientRequest(iUrl, iUrl.getBytes().length, startTime, request.getRemoteAddr(),
                        request.getMethod());

                User user = checkLogin(request, personalCode, em);

                ogcrequest.checkRequestURL();

                Organization mainOrg = null;
                String userName = null;

                if (user != null) {
                    mainOrg = user.getMainOrganization();
                    userName = user.getUsername();
                }

                rr.setUserAndOrganization(user, mainOrg);
                data.setHeader("X-Kaartenbalie-User", userName);

                parseRequestAndData(data, user);

            } catch (AccessDeniedException adex) {
                rr.setClientRequestException(adex);
                response.addHeader("WWW-Authenticate", "Basic realm=\"Kaartenbalie login\"");
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access denied to Kaartenbalie");
            } catch (ProviderException pex) {
                log.error("Error while communicating with provider: " + pex.getLocalizedMessage());
                rr.setClientRequestException(pex);
                handleRequestException(pex, data);
            } catch (Exception e) {
                log.error(String.format("Error while handling request for URI %s, query string %s: %s: %s",
                        request.getRequestURI(), request.getQueryString(), e.getClass().getName(), e.getMessage()),
                        e);
                rr.setClientRequestException(e);
                handleRequestException(e, data);
            } finally {
                rr.endClientRequest(serviceName, data.getOperation(), data.getContentLength(),
                        System.currentTimeMillis() - startTime);
            }
            if (!tx.getRollbackOnly()) {
                tx.commit();
            }
        } catch (Exception ex) {
            log.error("Error creating EntityManager", ex);
            handleRequestException(ex, data);
        } finally {
            if (tx != null && tx.isActive()) {
                tx.rollback();
            }
            MyEMFDatabase.closeEntityManager(identity, MyEMFDatabase.MAIN_EM);
        }
    }

    protected void handleRequestException(Exception ex, DataWrapper data) throws IOException {
        OGCRequest ogcrequest = data.getOgcrequest();

        if (ogcrequest == null) {
            data.setContentType(OGCConstants.WMS_PARAM_EXCEPTION_XML);
            handleRequestExceptionAsXML(ex, data);
        } else if (ogcrequest.getParameter(OGCConstants.SERVICE) != null
                && ogcrequest.getParameter(OGCConstants.SERVICE).equals(OGCConstants.WFS_SERVICE_WFS)) {
            data.setContentType(OGCConstants.WMS_PARAM_EXCEPTION_XML);
            handleRequestExceptionAsXML(ex, data);
        } else {
            String exType = "";
            if (ogcrequest.containsParameter(OGCConstants.WMS_PARAM_EXCEPTIONS)) {
                exType = ogcrequest.getParameter(OGCConstants.WMS_PARAM_EXCEPTIONS);
            }
            String requestparam = "";
            if (ogcrequest.containsParameter(OGCConstants.REQUEST)) {
                requestparam = ogcrequest.getParameter(OGCConstants.REQUEST);
            }
            if ((requestparam.equalsIgnoreCase(OGCConstants.WMS_REQUEST_GetMap)
                    || requestparam.equalsIgnoreCase(OGCConstants.WMS_REQUEST_GetLegendGraphic))
                    && (exType.equalsIgnoreCase(OGCConstants.WMS_PARAM_EXCEPTION_INIMAGE)
                            || exType.equalsIgnoreCase(OGCConstants.WMS_PARAM_SHORT_EXCEPTION_INIMAGE))
                    && ogcrequest.containsParameter(OGCConstants.WMS_PARAM_FORMAT)
                    && ogcrequest.containsParameter(OGCConstants.WMS_PARAM_WIDTH)
                    && ogcrequest.containsParameter(OGCConstants.WMS_PARAM_HEIGHT)) {
                data.setContentType(ogcrequest.getParameter(OGCConstants.WMS_PARAM_FORMAT));
                handleRequestExceptionAsImage(ex, data);
            } else {
                data.setContentType(OGCConstants.WMS_PARAM_EXCEPTION_XML);
                handleRequestExceptionAsXML(ex, data);
            }
        }
    }

    private void handleRequestExceptionAsImage(Exception ex, DataWrapper data) throws IOException {
        String message = ex.getMessage();
        try {
            ExceptionLayer el = new ExceptionLayer();
            Map parameterMap = new HashMap();
            parameterMap.put("type", ex.getClass());
            parameterMap.put("transparant", Boolean.TRUE);
            parameterMap.put("message", message);
            parameterMap.put("stacktrace", ex.getStackTrace());
            el.sendImage(data, el.drawImage(data.getOgcrequest(), parameterMap));
        } catch (Exception e) {
            log.error("error handling exception: ", e);
            TextToImage tti = new TextToImage();
            try {
                tti.createImage(message, data);
            } catch (Exception lex) {
                log.error("error creating error-image: ", lex);
            }
        }
    }

    private void handleRequestExceptionAsXML(Exception ex, DataWrapper data) throws IOException {
        ByteArrayOutputStream output = null;
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setValidating(false);
        dbf.setNamespaceAware(true);
        DocumentBuilder db = null;
        try {
            db = dbf.newDocumentBuilder();
        } catch (Exception e) {
            log.error("error: ", e);
            throw new IOException("Exception occured during creation of error message: " + e);
        }

        DOMImplementation di = db.getDOMImplementation();

        // <!DOCTYPE ServiceExceptionReport SYSTEM "http://schemas.opengeospatial.net/wms/1.1.1/exception_1_1_1.dtd"
        // <!-- end of DOCTYPE declaration -->
        DocumentType dt = di.createDocumentType("ServiceExceptionReport", null, CallWMSServlet.EXCEPTION_DTD);
        Document dom = di.createDocument(null, "ServiceExceptionReport", dt);
        Element rootElement = dom.getDocumentElement();
        rootElement.setAttribute("version", "1.1.1");

        Element serviceExceptionElement = dom.createElement("ServiceException");

        String exceptionName = ex.getClass().getName();
        String message = ex.getMessage();
        Throwable cause = ex.getCause();

        serviceExceptionElement.setAttribute("code", exceptionName);
        CDATASection cdata = null;
        if (cause != null) {
            cdata = dom.createCDATASection(message + " - " + cause);
        } else {
            cdata = dom.createCDATASection(message);
        }

        serviceExceptionElement.appendChild(cdata);
        rootElement.appendChild(serviceExceptionElement);

        OutputFormat format = new OutputFormat(dom);
        format.setIndenting(true);
        output = new ByteArrayOutputStream();
        XMLSerializer serializer = new XMLSerializer(output, format);
        serializer.serialize(dom);

        DOMValidator dv = new DOMValidator();
        try {
            dv.parseAndValidate(new ByteArrayInputStream(output.toString().getBytes(KBConfiguration.CHARSET)));
        } catch (Exception e) {
            log.error("error: ", e);
            throw new IOException("Exception occured during validation of error message: " + e);
        }

        data.setHeader("Content-Disposition", "inline; filename=\"ServiceException.xml\";");
        data.write(output);
    }

    /** Checks if an user is allowed to make any requests.
     * Therefore there is checked if a user is logged in or if a user is using a private unique IP address.
     *
     * @param parameters The parameters of a given request
     *
     * @return Map with the same parameters and same key all in uppercase
     */
    // <editor-fold defaultstate="" desc="getUpperCaseParameterMap(Map parameters) method.">
    private Map getUpperCaseParameterMap(Map parameters) {
        Map newParameterMap = new HashMap();
        Set paramKeySet = parameters.keySet();
        Iterator keySetIterator = paramKeySet.iterator();
        while (keySetIterator.hasNext()) {
            String key = (String) keySetIterator.next();
            String value = ((String[]) parameters.get(key))[0];

            String caseInsensitiveKey = key.toUpperCase();
            String caseInsensitiveValue = value.toUpperCase();

            newParameterMap.put(caseInsensitiveKey, caseInsensitiveValue);
        }
        return newParameterMap;
    }
    // </editor-fold>

    /** Parses any incoming request and redirects this request to the right handler.
     *
     * @param parameters map with the given parameters
     *
     * @return byte array with the requested data
     *
     * @throws IllegalArgumentException
     * @throws UnsupportedOperationException
     * @throws IOException
     */
    public void parseRequestAndData(DataWrapper data, User user)
            throws IllegalArgumentException, UnsupportedOperationException, IOException, Exception {
        String request = data.getOgcrequest().getParameter(OGCConstants.REQUEST);
        String service = data.getOgcrequest().getParameter(OGCConstants.SERVICE);

        RequestHandler requestHandler = null;
        if (service != null && service.length() > 0) {
            if (service.equalsIgnoreCase(OGCConstants.NONOGC_SERVICE_PROXY)) {
                requestHandler = new ProxyRequestHandler();
            } else if (service.equalsIgnoreCase(OGCConstants.NONOGC_SERVICE_METADATA)) {
                requestHandler = new MetadataRequestHandler();
            } else if (service.equalsIgnoreCase(OGCConstants.WMS_SERVICE_WMS)) {
                if (request.equalsIgnoreCase(OGCConstants.WMS_REQUEST_GetCapabilities)) {
                    requestHandler = new GetCapabilitiesRequestHandler();
                }
            } else if (service.equalsIgnoreCase(OGCConstants.WFS_SERVICE_WFS)) {
                if (request.equalsIgnoreCase(OGCConstants.WFS_REQUEST_GetCapabilities)) {
                    requestHandler = new WFSGetCapabilitiesRequestHandler();
                }
            }
        }

        if (requestHandler == null) {
            if (request.equalsIgnoreCase(OGCConstants.WMS_REQUEST_GetMap)) {
                requestHandler = new GetMapRequestHandler();
                service = OGCConstants.WMS_SERVICE_WMS;
            } else if (request.equalsIgnoreCase(OGCConstants.WMS_REQUEST_GetFeatureInfo)) {
                requestHandler = new GetFeatureInfoRequestHandler();
                service = OGCConstants.WMS_SERVICE_WMS;
            } else if (request.equalsIgnoreCase(OGCConstants.WMS_REQUEST_GetLegendGraphic)) {
                requestHandler = new GetLegendGraphicRequestHandler();
                service = OGCConstants.WMS_SERVICE_WMS;
            } else if (request.equalsIgnoreCase(OGCConstants.WMS_REQUEST_DescribeLayer)) {
                requestHandler = new DescribeLayerRequestHandler();
                service = OGCConstants.WMS_SERVICE_WMS;
            } else if (request.equalsIgnoreCase(OGCConstants.WFS_REQUEST_DescribeFeatureType)) {
                requestHandler = new WFSDescribeFeatureTypeRequestHandler();
                service = OGCConstants.WFS_SERVICE_WFS;
            } else if (request.equalsIgnoreCase(OGCConstants.WFS_REQUEST_GetFeature)) {
                requestHandler = new WFSGetFeatureRequestHandler();
                service = OGCConstants.WFS_SERVICE_WFS;
            } else if (request.equalsIgnoreCase(OGCConstants.WFS_REQUEST_Transaction)) {
                requestHandler = new WFSTransactionRequestHandler();
                service = OGCConstants.WFS_SERVICE_WFS;
            }
        }

        if (requestHandler == null) {
            throw new UnsupportedOperationException("Request " + request + " is not suported!");
        }

        data.setOperation(request);
        data.setService(service);
        requestHandler.getRequest(data, user);

    }

    /** Returns a short description of the servlet.
     */
    @Override
    public String getServletInfo() {
        return "CallWMSServlet info";
    }

}