nl.opengeogroep.dbk.DBKAPI.java Source code

Java tutorial

Introduction

Here is the source code for nl.opengeogroep.dbk.DBKAPI.java

Source

/*
 * Copyright (C) 2014 B3Partners B.V.
 *
 * This program 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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package nl.opengeogroep.dbk;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONObject;
import org.apache.commons.io.IOUtils;

/**
 *
 * @author Meine Toonen
 */
public class DBKAPI extends HttpServlet {

    private static final Log log = LogFactory.getLog(DBKAPI.class);
    private static final String API_PART = "/api/";
    private static final String FEATURES = "features.json";
    private static final String OBJECT = "object/";
    private static final String GEBIED = "gebied/";
    private static final String MEDIA = "media/";
    private static final String JSON = ".json";

    private static final String PARAMETER_SRID = "srid";

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, SQLException {
        String method = null;
        OutputStream out = response.getOutputStream();
        try {
            String requestedUri = request.getRequestURI();
            method = requestedUri.substring(requestedUri.indexOf(API_PART) + API_PART.length());
            JSONObject output = new JSONObject();
            if (method.contains(FEATURES) || method.contains(OBJECT) || method.contains(GEBIED)) {
                if (method.contains(FEATURES)) {
                    output = processFeatureRequest(request);
                } else if (method.contains(OBJECT)) {
                    output = processObjectRequest(request, method);
                } else {
                    output = processGebiedRequest(request, method);
                }
                response.setContentType("application/json;charset=UTF-8");
                out.write(output.toString().getBytes("UTF-8"));
            } else if (method.contains(MEDIA)) {
                processMedia(method, request, response, out);
            } else {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                output.put("success", Boolean.FALSE);
                output.put("message", "Requested method not understood. Method was: " + method
                        + " but expected are: " + FEATURES + ", " + OBJECT + " or " + MEDIA);
                out.write(output.toString().getBytes());
            }
        } catch (IllegalArgumentException ex) {
            response.setContentType("text/plain;charset=UTF-8");
            log.error("Error happened with " + method + ":", ex);
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            out.write(ex.getLocalizedMessage().getBytes());
        } catch (Exception e) {
            log.error("Error happened with " + method + ":", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            out.write(("Exception occured:" + e.getLocalizedMessage()).getBytes());
        } finally {
            out.flush();
            out.close();
        }
    }

    /**
     * Process the call to /api/features.json[?srid=<integer>]
     * @param request The requestobject
     * @return A JSONObject with the GeoJSON representation of all the DBK's
     * @throws SQLException 
     */
    private JSONObject processFeatureRequest(HttpServletRequest request) throws SQLException, Exception {
        JSONObject geoJSON = new JSONObject();
        JSONArray jFeatures = new JSONArray();
        boolean hasParameter = request.getParameter(PARAMETER_SRID) != null;
        Connection conn = getConnection();
        if (conn == null) {
            throw new Exception("Connection could not be established");
        }
        MapListHandler h = new MapListHandler();
        QueryRunner run = new QueryRunner();

        geoJSON.put("type", "FeatureCollection");
        geoJSON.put("features", jFeatures);
        try {
            List<Map<String, Object>> features;
            if (hasParameter) {
                String sridString = request.getParameter(PARAMETER_SRID);
                Integer srid = Integer.parseInt(sridString);
                features = run.query(conn, "select \"feature\" from dbk.dbkfeatures_json(?)", h, srid);
            } else {
                features = run.query(conn, "select \"feature\" from dbk.dbkfeatures_json()", h);
            }

            for (Map<String, Object> feature : features) {
                JSONObject jFeature = processFeature(feature);
                jFeatures.put(jFeature);
            }
        } finally {
            DbUtils.close(conn);
        }
        return geoJSON;
    }

    /**
     * Method for requesting a single DBKObject
     * @param request The HttpServletRequest of this request
     * @param method Method containing possible (mandatory!) parameters: the id
     * @return An JSONObject representing the requested DBKObject, of an empty JSONObject if none is found
     * @throws Exception 
     */
    private JSONObject processObjectRequest(HttpServletRequest request, String method) throws Exception {
        JSONObject json = new JSONObject();
        boolean hasSrid = request.getParameter(PARAMETER_SRID) != null;
        Connection conn = getConnection();
        if (conn == null) {
            throw new Exception("Connection could not be established");
        }
        MapHandler h = new MapHandler();
        QueryRunner run = new QueryRunner();

        String idString = null;
        Integer id = null;
        try {
            idString = method.substring(method.indexOf(OBJECT) + OBJECT.length(), method.indexOf(JSON));
            id = Integer.parseInt(idString);
        } catch (NumberFormatException ex) {
            throw new IllegalArgumentException("Given id not correct, should be an integer. Was: " + idString);
        }
        try {
            Map<String, Object> feature;
            if (hasSrid) {
                String sridString = request.getParameter(PARAMETER_SRID);
                Integer srid = Integer.parseInt(sridString);
                feature = run.query(conn, "select \"DBKObject\" from dbk.dbkobject_json(?,?)", h, id, srid);
            } else {
                feature = run.query(conn, "select \"DBKObject\" from dbk.dbkobject_json(?)", h, id);
            }
            if (feature == null) {
                throw new IllegalArgumentException("Given id didn't yield any results.");
            }
            JSONObject pgObject = new JSONObject(feature.get("DBKObject"));
            json = new JSONObject();
            json.put("DBKObject", new JSONObject(pgObject.getString("value")));

        } finally {
            DbUtils.close(conn);
        }
        return json;
    }

    private JSONObject processGebiedRequest(HttpServletRequest request, String method) throws Exception {
        JSONObject json = new JSONObject();
        boolean hasSrid = request.getParameter(PARAMETER_SRID) != null;
        Connection conn = getConnection();
        if (conn == null) {
            throw new Exception("Connection could not be established");
        }
        MapHandler h = new MapHandler();
        QueryRunner run = new QueryRunner();

        String idString = null;
        Integer id = null;
        try {
            idString = method.substring(method.indexOf(GEBIED) + GEBIED.length(), method.indexOf(JSON));
            id = Integer.parseInt(idString);
        } catch (NumberFormatException ex) {
            throw new IllegalArgumentException("Given id not correct, should be an integer. Was: " + idString);
        }
        try {
            Map<String, Object> feature;
            if (hasSrid) {
                String sridString = request.getParameter(PARAMETER_SRID);
                Integer srid = Integer.parseInt(sridString);
                feature = run.query(conn, "select \"DBKGebied\" from dbk.dbkgebied_json(?,?)", h, id, srid);
            } else {
                feature = run.query(conn, "select \"DBKGebied\" from dbk.dbkgebied_json(?)", h, id);
            }
            if (feature == null) {
                throw new IllegalArgumentException("Given id didn't yield any results.");
            }
            JSONObject pgObject = new JSONObject(feature.get("DBKGebied"));
            json = new JSONObject();
            json.put("DBKGebied", new JSONObject(pgObject.getString("value")));

        } finally {
            DbUtils.close(conn);
        }
        return json;
    }

    /**
     * Processes the request for retrieving the media belonging to a DBK.
     * @param method The part of the url after /api/, containing the file name (and possible subdirectory)
     * @param request The http request
     * @param response The http response
     * @param out The outputstream to which the file must be written.
     * @throws IOException 
     */
    private void processMedia(String method, HttpServletRequest request, HttpServletResponse response,
            OutputStream out) throws IOException {
        FileInputStream fis = null;
        File requestedFile = null;
        String basePath = request.getServletContext().getInitParameter("dbk.media.path");
        try {
            String fileArgument = method.substring(method.indexOf(MEDIA) + MEDIA.length());
            String totalPath = basePath + File.separatorChar + fileArgument;

            totalPath = URLDecoder.decode(totalPath, response.getCharacterEncoding());
            requestedFile = new File(totalPath);

            fis = new FileInputStream(requestedFile);
            response.setContentType(request.getServletContext().getMimeType(totalPath));
            Long size = requestedFile.length();
            response.setContentLength(size.intValue());
            IOUtils.copy(fis, out);
        } catch (IOException ex) {
            log.error("Error retrieving media.", ex);
            if (requestedFile != null) {
                log.error("Cannot load media: " + requestedFile.getCanonicalPath() + " from basePath: " + basePath);
            }
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
        } finally {
            if (fis != null) {
                fis.close();
            }
        }
    }

    private JSONObject processFeature(Map<String, Object> feature) {
        JSONObject jsonFeature = new JSONObject();
        JSONObject properties = new JSONObject();

        JSONObject dbFeatureObject = new JSONObject(feature.get("feature"));
        JSONObject featureValues = new JSONObject(dbFeatureObject.getString("value"));

        jsonFeature.put("type", "Feature");
        jsonFeature.put("id", "DBKFeature.gid--" + featureValues.get("gid"));
        jsonFeature.put("geometry", featureValues.get("geometry"));

        jsonFeature.put("properties", properties);
        for (Iterator it = featureValues.keys(); it.hasNext();) {
            String key = (String) it.next();
            if (key.equals("geometry")) {
                continue;
            }
            Object value = featureValues.get(key);
            properties.put(key, value);
        }
        return jsonFeature;
    }

    public Connection getConnection() {
        try {
            InitialContext cxt = new InitialContext();
            if (cxt == null) {
                throw new Exception("Uh oh -- no context!");
            }

            DataSource ds = (DataSource) cxt.lookup("java:/comp/env/jdbc/dbk-api");

            if (ds == null) {
                throw new Exception("Data source not found!");
            }
            Connection connection = ds.getConnection();
            return connection;
        } catch (NamingException ex) {
            log.error("naming", ex);
        } catch (Exception ex) {
            log.error("exception", ex);
        }
        return null;
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (SQLException ex) {
            log.error("GET failed: ", ex);
        }
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (SQLException ex) {
            log.error("POST failed: ", ex);
        }
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

}