nersc.greenseas.portlet.GreenseasPortlet.java Source code

Java tutorial

Introduction

Here is the source code for nersc.greenseas.portlet.GreenseasPortlet.java

Source

/**
 *  GreenseasPortlet -  a portlet to view and extract values from the GreenSeas
 *  Analytical Database.
 *  
 *  Copyright (C) 2013 Nansen Environmental and Remote Sensing Center (NERSC)
 *
 *  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 nersc.greenseas.portlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipOutputStream;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.servlet.http.HttpServletRequest;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import nersc.greenseas.configuration.DatabaseProperties;
import nersc.greenseas.rasterData.NetCDFReader;
import nersc.greenseas.rasterData.NetCDFWriter;

import com.liferay.portal.kernel.servlet.HttpHeaders;
import com.liferay.portal.kernel.upload.UploadPortletRequest;
import com.liferay.portal.util.PortalUtil;
import com.liferay.portlet.PortletURLUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;

/**
 * GreenSeasPortlet displays the location of oceanographic measurements on a map
 * and allows extraction of data within a user defined geographic area.
 * 
 * @author Aleksander Vines
 * 
 */
public class GreenseasPortlet extends MVCPortlet {

    @Override
    public void doView(RenderRequest renderRequest, RenderResponse renderResponse)
            throws IOException, PortletException {
        // TODO: validate/escape to prevent injection
        renderRequest.setAttribute("allParametersHeader", DatabaseProperties.getAllParametersHeader());
        renderRequest.setAttribute("allParametersShortHeader", DatabaseProperties.getAllParametersShortHeader());
        renderRequest.setAttribute("allParametersTooltips", DatabaseProperties.getAllParametersTooltips());
        renderRequest.setAttribute("allParametersUnit", DatabaseProperties.getAllParametersUnit());
        renderRequest.setAttribute("allParametersDataType", DatabaseProperties.getAllParametersDataType());
        renderRequest.setAttribute("allLayers", DatabaseProperties.getAllLayers());
        renderRequest.setAttribute("allProperties", DatabaseProperties.getAllProperties());
        renderRequest.setAttribute("longhurstRegions", DatabaseProperties.getLonghurstRegions());
        renderRequest.setAttribute("combinedParameters", DatabaseProperties.getCombinedParameters());
        renderRequest.setAttribute("wmsLayers", DatabaseProperties.getWmsLayers());
        renderRequest.setAttribute("openDAPURLs", DatabaseProperties.getOpenDAPURLs());
        renderRequest.setAttribute("cruisesList", DatabaseProperties.getCruisesList());
        HttpServletRequest request = PortalUtil.getHttpServletRequest(renderRequest);
        String query = PortalUtil.getOriginalServletRequest(request).getParameter("query");
        renderRequest.setAttribute("linkedQuery", query);
        PortletURL url = PortletURLUtil.getCurrent(renderRequest, renderResponse);
        renderRequest.setAttribute("portletURL", url.toString().split("\\?")[0].split(";")[0]);
        super.doView(renderRequest, renderResponse);
    }

    @Override
    public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse)
            throws IOException, PortletException {
        System.out.println("Calling serveResource");
        resourceResponse.setContentType("text/javascript");
        String uri = resourceRequest.getParameter("fileID");
        String requestType = resourceRequest.getParameter("requestType");
        System.out.println("requestType:'" + requestType + "'");
        String opendapDataURL = resourceRequest.getParameter("opendapDataURL");
        if (requestType != null) {
            if (requestType.equals("serveNetCDFFile")) {
                String location = resourceRequest.getParameter("fileID");
                if (location != null) {
                    String[] folders = { "content", "gsadbc", "createdFiles" };
                    String filePath = createDirectory(System.getProperty("catalina.base"), folders);
                    for (int i = 0; i < location.length(); i++) {
                        char c = uri.charAt(i);
                        if (c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || c > 'z')
                            throw new InvalidFileNameException(
                                    "Invalid file name (illegal character:'" + c + "'):" + uri);
                    }
                    String fileExtension = ".nc";
                    location = filePath + location + fileExtension;
                    resourceResponse.setContentType("application/octet-stream");
                    resourceResponse.setProperty("Content-Disposition",
                            "attachment;filename=\"Greenseas_Downloaded_Parameters.nc\"");
                    OutputStream out = resourceResponse.getPortletOutputStream();

                    //               Content-Type: application/octet-stream
                    //               Content-Disposition: attachment;filename=\"filename.xxx\"
                    InputStream in = null;
                    try {
                        in = new FileInputStream(new File(location));
                        if (in != null) {
                            byte[] buffer = new byte[4096];
                            int len;

                            while ((len = in.read(buffer)) != -1) {
                                out.write(buffer, 0, len);
                            }

                            out.flush();
                            System.out.println("Wrote nc file to outputstream");
                        }
                    } catch (Exception e) {
                        // TODO: handle exception
                    } finally {
                        if (in != null)
                            in.close();
                        if (out != null)
                            out.close();
                    }
                }
                return;
            }
            if (uri != null || opendapDataURL != null) {
                if (opendapDataURL == null) {
                    String[] folders = { "content", "gsadbc", "uploadedFiles" };
                    String filePath = createDirectory(System.getProperty("catalina.base"), folders);
                    for (int i = 0; i < uri.length(); i++) {
                        char c = uri.charAt(i);
                        if (c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || c > 'z')
                            throw new InvalidFileNameException(
                                    "Invalid file name (illegal character:'" + c + "'):" + uri);
                    }
                    String fileExtension = ".nc";
                    uri = filePath + uri + fileExtension;
                } else {
                    uri = opendapDataURL;
                }
                if (requestType.startsWith("getDataValuesOf:")) {
                    System.out.println("requestType is getDataValuesOf:");
                    Map<String, String[]> parameterMap = resourceRequest.getParameterMap();
                    Map<Integer, Map<String, Double>> values = NetCDFReader.getDatavaluesFromNetCDFFile(uri,
                            parameterMap);
                    if (values == null)
                        return;
                    JSONObject jsonObject = new JSONObject(values);
                    // System.out.println("Returning with jsonObject:");
                    // System.out.println(jsonObject.toJSONString());

                    PrintWriter writer = resourceResponse.getWriter();
                    writer.write(jsonObject.toString());
                    return;
                } else if (requestType.equals("getLayersFromNetCDFFile")) {
                    System.out.println("requestType is getLayersFromNetCDFFile:");
                    System.out.println("opendapDataURL:" + opendapDataURL);
                    System.out.println("uri:" + uri);
                    Map<String, String> values = NetCDFReader.getLayersFromRaster(uri);
                    if (values == null) {
                        System.out.println("No values found!");
                        return;
                    }
                    JSONObject jsonObject = new JSONObject(values);

                    System.out.println("Returning with jsonObject:");
                    System.out.println(jsonObject.toJSONString());

                    PrintWriter writer = resourceResponse.getWriter();
                    writer.write(jsonObject.toString());
                    return;
                } else if (requestType.equals("getMetaDimensions")) {
                    System.out.println("getMetaDimensions:" + uri);
                    String parameter = resourceRequest.getParameter("rasterParameter");
                    if (parameter == null)
                        return;
                    Map<String, Map<String, String>> values = NetCDFReader.getDimensionsFromRasterParameter(uri,
                            parameter);
                    if (values == null)
                        return;
                    JSONObject jsonObject = new JSONObject(values);

                    System.out.println("Returning with jsonObject:");
                    System.out.println(jsonObject.toJSONString());

                    PrintWriter writer = resourceResponse.getWriter();
                    writer.write(jsonObject.toString());
                    return;
                } else if (requestType.equals("loadFileFromID")) {
                    //TODO: fix security hole
                    System.out.println(uri);
                    JSONObject jsonObject = new JSONObject();
                    File f = new File(uri);
                    boolean exists = f.exists();
                    // sleep for 1 seconds to mitigate brute force attacks
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    jsonObject.put("fileIDExists", exists);
                    PrintWriter writer = resourceResponse.getWriter();
                    writer.write(jsonObject.toString());
                    return;
                }
            }
            if (requestType.equals("getLonghurstPolygon")) {
                Map<String, String> values = new HashMap<String, String>();
                String region = resourceRequest.getParameter("longhurstRegion");
                System.out.println("getLonghurstPolygon:" + region);
                String polygon = DatabaseProperties.getLonghurstPolygon(region);
                values.put(region, polygon);
                JSONObject jsonObject = new JSONObject(values);

                System.out.println("Returning with polygon!=null:" + (polygon != null));

                PrintWriter writer = resourceResponse.getWriter();
                writer.write(jsonObject.toString());
                return;
            } else if (requestType.equals("createNetCDFUsingH.1")) {
                JSONParser parser = new JSONParser();
                JSONArray jsonA = null;
                JSONObject jsonO = null;
                int numberOfFeatures = 0;
                try {
                    jsonA = (JSONArray) parser.parse(resourceRequest.getParameter("data"));
                    String variablesString = resourceRequest.getParameter("variables");
                    numberOfFeatures = Integer.parseInt(resourceRequest.getParameter("numberOfFeatures"));
                    System.out.println(variablesString);
                    jsonO = (JSONObject) parser.parse(variablesString);
                } catch (ParseException e) {
                }
                String[] folders = { "content", "gsadbc", "createdFiles" };
                String filePath = createDirectory(System.getProperty("catalina.base"), folders);

                String fileID = NetCDFWriter.createNetCDF(jsonA, jsonO, numberOfFeatures, filePath);
                Map<String, String> values = new HashMap<String, String>();

                values.put("fileID", fileID);
                JSONObject jsonObject = new JSONObject(values);

                /*resourceResponse.setContentType("application/x-netcdf");
                resourceResponse.addProperty(HttpHeaders.CACHE_CONTROL, "max-age=3600, must-revalidate");
                    
                OutputStream out = resourceResponse.getPortletOutputStream();
                    
                InputStream in = new FileInputStream(new File(location));
                    
                byte[] buffer = new byte[4096];
                int len;
                    
                while ((len = in.read(buffer)) != -1) {
                   out.write(buffer, 0, len);
                }
                    
                out.flush();
                in.close();
                out.close();*/
                System.out.println("Returning with fileID" + fileID);

                PrintWriter writer = resourceResponse.getWriter();
                writer.write(jsonObject.toString());
                return;
            } else if (requestType.equals("getLonghurstPolygon")) {
                Map<String, String> values = new HashMap<String, String>();
                String region = resourceRequest.getParameter("longhurstRegion");
                System.out.println("getLonghurstPolygon:" + region);
                String polygon = DatabaseProperties.getLonghurstPolygon(region);
                values.put(region, polygon);
                JSONObject jsonObject = new JSONObject(values);

                System.out.println("Returning with polygon!=null:" + (polygon != null));

                PrintWriter writer = resourceResponse.getWriter();
                writer.write(jsonObject.toString());
                return;
            } else if (requestType.equals("updateTreeWithInventoryNumbers")) {
                String urlS = resourceRequest.getParameter("url");
                String region = resourceRequest.getParameter("gsadbcRegionFilterPlaceHolder");
                if (region != null) {
                    region = region.substring(51, region.length() - 13);
                }
                JSONParser parser = new JSONParser();
                JSONObject jsonO = null;
                try {
                    jsonO = (JSONObject) parser.parse(resourceRequest.getParameter("data"));
                } catch (ParseException e) {
                }
                String charset = "UTF-8";
                int numberOfThreads = 4;
                Set<?> entrySet = jsonO.keySet();
                ArrayList<Map<String, String>> responseMaps = new ArrayList<Map<String, String>>();
                ArrayList<Map<String, String>> requestMaps = new ArrayList<Map<String, String>>();
                for (int i = 0; i < numberOfThreads; i++) {
                    responseMaps.add(new HashMap<String, String>());
                    requestMaps.add(new HashMap<String, String>());
                }

                int thredd = 0;
                for (Object o : entrySet) {
                    String key = (String) o;
                    String request = (String) jsonO.get(key);
                    requestMaps.get(thredd).put(key, request);
                    thredd = (thredd + 1) % numberOfThreads;
                }
                ArrayList<GetNumberOfFeatures> threadds = new ArrayList<GetNumberOfFeatures>();
                for (int i = 0; i < numberOfThreads; i++) {
                    GetNumberOfFeatures runnable = new GetNumberOfFeatures(responseMaps.get(i), requestMaps.get(i),
                            charset, urlS, i, region);
                    Thread thread = new Thread(runnable);
                    thread.start();
                    threadds.add(runnable);
                }
                while (true) {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    boolean done = true;
                    for (int i = 0; i < numberOfThreads; i++) {
                        if (!threadds.get(i).done) {
                            done = false;
                            break;
                        }
                    }
                    if (done)
                        break;
                }
                Map<String, String> responseMap = new HashMap<String, String>();

                for (int i = 0; i < numberOfThreads; i++) {
                    responseMap.putAll(responseMaps.get(i));
                }
                JSONObject jsonObject = new JSONObject(responseMap);
                PrintWriter writer = resourceResponse.getWriter();
                writer.write(jsonObject.toString());
                return;
            }
        } else {

        }
    }

    private static String placeHolder = "<ogc:Within><ogc:PropertyName>point</ogc:PropertyName><gml:Envelope xmlns:gml=\"http://www.opengis.net/gml\"><gml:lowerCorner>undefined undefined</gml:lowerCorner><gml:upperCorner>undefined undefined</gml:upperCorner></gml:Envelope></ogc:Within>";

    class GetNumberOfFeatures implements Runnable {

        public GetNumberOfFeatures(Map<String, String> responseMap, Map<String, String> requestMap, String charset,
                String url, int number, String region) {
            super();
            this.responseMap = responseMap;
            this.requestMap = requestMap;
            this.charset = charset;
            this.urlS = url;
            this.number = number;
            this.region = region;
        }

        Map<String, String> responseMap, requestMap;
        String charset, urlS, region;
        boolean done = false;
        int number;

        @Override
        public void run() {
            try {
                for (String key : requestMap.keySet()) {
                    URL url = new URL(urlS);
                    String requestS = (String) requestMap.get(key);
                    if (region != null) {
                        requestS = requestS.replace(GreenseasPortlet.placeHolder, region);
                    }
                    byte[] request = requestS.getBytes(charset);
                    URLConnection connection = url.openConnection();
                    // POST REQUEST!
                    connection.setDoOutput(true);
                    connection.setRequestProperty("Accept-Charset", charset);
                    connection.setRequestProperty("Content-Type", "text/xml;charset=" + charset);
                    OutputStream wr = connection.getOutputStream();
                    try {
                        wr.write(request);
                    } finally {
                        wr.flush();
                        wr.close();
                    }
                    InputStream response = connection.getInputStream();
                    String numberOfFeatures = getNumberOfFeatures(response);
                    if (numberOfFeatures == null)
                        numberOfFeatures = "An error occured";
                    responseMap.put(key, numberOfFeatures);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            done = true;
        }
    }

    public String getNumberOfFeatures(InputStream in) {
        String searchingFor = "numberOfFeatures=\"";
        int length = searchingFor.length();
        int index = 0;
        boolean found = false;
        String result = "";
        while (true) {
            try {
                int nextI = in.read();
                if (nextI == -1)
                    return null;
                char next = (char) nextI;
                if (found) {
                    if (next == '"') {
                        break;
                    } else {
                        result += next;
                    }
                } else {
                    if (next == searchingFor.charAt(index)) {
                        index++;
                        if (index == length) {
                            found = true;
                        }
                    } else {
                        index = 0;
                    }
                }

            } catch (IOException e) {
                return null;
            }
        }
        return result;
    }

    private static String createRandomString(int number) {
        SecureRandom sr = new SecureRandom();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < number; i++) {
            int randomInt = sr.nextInt(62);
            char nextChar = '_';
            if (randomInt < 10) {
                nextChar = (char) (randomInt + 48);
            } else if (randomInt < 36) {
                nextChar = (char) (randomInt + 55);
            } else {
                nextChar = (char) (randomInt + 61);
            }
            sb.append(nextChar);
        }
        return sb.toString();
    }

    public void submitFile(ActionRequest actionRequest, ActionResponse actionResponse) throws Exception {
        UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(actionRequest);

        // uploaded filename
        String randomFileName = createRandomString(30);
        String fileExtension = ".nc";

        // uploaded file you can see it in /tomcat/temp is moved to
        // /tomcat/content/gsadbc/uploadedFiles
        File submissionFile = uploadRequest.getFile("file");
        System.out.println("Uploaded files");
        String[] folders = { "content", "gsadbc", "uploadedFiles" };
        String filePath = createDirectory(System.getProperty("catalina.base"), folders);
        String fileURI = filePath + randomFileName + fileExtension;
        moveFile(submissionFile.getAbsolutePath(), fileURI);

        actionResponse.addProperty("fileID", randomFileName);
    }

    private String createDirectory(String base, String[] subFolders) {
        base += File.separator;
        File directory = new File(base);
        // if the directory does not exist, create it
        if (directory.exists()) {
            for (int i = 0; i < subFolders.length; i++) {
                base += subFolders[i] + File.separator;
                directory = new File(base);
                if (!directory.exists()) {
                    System.out.println("creating directory: " + base);
                    boolean result = directory.mkdir();

                    if (result) {
                        System.out.println("DIR created");
                    } else {
                        System.out.println("Did not manage to create '" + base + "'");
                        return null;
                    }
                }
            }
        } else
            return null;
        return base;
    }

    private boolean moveFile(String moveFrom, String moveTo) {
        InputStream inStream = null;
        OutputStream outStream = null;

        try {

            File afile = new File(moveFrom);
            File bfile = new File(moveTo);

            inStream = new FileInputStream(afile);
            outStream = new FileOutputStream(bfile);

            byte[] buffer = new byte[1024];

            int length;
            // copy the file content in bytes
            while ((length = inStream.read(buffer)) > 0) {

                outStream.write(buffer, 0, length);

            }

            inStream.close();
            outStream.close();

            // delete the original file
            afile.delete();

            System.out.println("File is copied successful from '" + moveFrom + "' to '" + moveTo + "'");
            return true;

        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
}