nz.co.fortytwo.signalk.processor.UploadProcessor.java Source code

Java tutorial

Introduction

Here is the source code for nz.co.fortytwo.signalk.processor.UploadProcessor.java

Source

/*
 *
 * Copyright (C) 2012-2014 R T Huitema. All Rights Reserved.
 * Web: www.42.co.nz
 * Email: robert@42.co.nz
 * Author: R T Huitema
 *
 * This file is part of the signalk-server-java project
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package nz.co.fortytwo.signalk.processor;

import static nz.co.fortytwo.signalk.util.ConfigConstants.MAP_DIR;
import static nz.co.fortytwo.signalk.util.ConfigConstants.STATIC_DIR;

import static nz.co.fortytwo.signalk.util.SignalKConstants.dot;
import static nz.co.fortytwo.signalk.util.SignalKConstants.name;
import static nz.co.fortytwo.signalk.util.SignalKConstants.resources;
import static nz.co.fortytwo.signalk.util.SignalKConstants.resources_charts;
import static nz.co.fortytwo.signalk.util.SignalKConstants.routes;
import static nz.co.fortytwo.signalk.util.SignalKConstants.value;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.component.http.HttpMessage;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.restlet.data.MediaType;
import org.restlet.ext.fileupload.RestletFileUpload;
import org.restlet.representation.InputRepresentation;

import mjson.Json;
import nz.co.fortytwo.signalk.util.SignalKConstants;
import nz.co.fortytwo.signalk.util.Util;
import nz.co.fortytwo.signalk.util.ZipUtils;

public class UploadProcessor extends SignalkProcessor implements Processor {
    private static Logger logger = LogManager.getLogger(UploadProcessor.class);

    @Override
    public void process(Exchange exchange) throws Exception {

        logger.debug("UploadProcessor starts");
        HttpServletRequest request = exchange.getIn(HttpMessage.class).getRequest();
        logger.debug("Session = " + request.getSession().getId());
        HttpSession session = request.getSession();
        if (logger.isDebugEnabled()) {

            logger.debug("Request = " + exchange.getIn().getHeader(Exchange.HTTP_SERVLET_REQUEST).getClass());
            logger.debug("Session = " + session.getId());
        }

        if (session.getId() != null) {

            String remoteAddress = request.getRemoteAddr();
            String localAddress = request.getLocalAddr();
            if (Util.sameNetwork(localAddress, remoteAddress)) {
                exchange.getIn().setHeader(SignalKConstants.MSG_TYPE, SignalKConstants.INTERNAL_IP);
            } else {
                exchange.getIn().setHeader(SignalKConstants.MSG_TYPE, SignalKConstants.EXTERNAL_IP);
            }
            if (exchange.getIn().getHeader(Exchange.HTTP_METHOD).equals("POST")) {
                processUpload(exchange);
            }
        } else {
            exchange.getIn().setHeader("Location", SignalKConstants.SIGNALK_AUTH);
            exchange.getIn().setBody("Authentication Required");
        }
    }

    private void processUpload(Exchange exchange) throws Exception {
        logger.debug("Begin import:" + exchange.getIn().getHeaders());
        if (exchange.getIn().getBody() != null) {
            logger.debug("Body class:" + exchange.getIn().getBody().getClass());
        } else {
            logger.debug("Body class is null");
        }
        //logger.debug("Begin import:"+ exchange.getIn().getBody());
        MediaType mediaType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, MediaType.class);
        InputRepresentation representation = new InputRepresentation((InputStream) exchange.getIn().getBody(),
                mediaType);
        logger.debug("Found MIME:" + mediaType + ", length:"
                + exchange.getIn().getHeader(Exchange.CONTENT_LENGTH, Integer.class));
        //make a reply
        Json reply = Json.read("{\"files\": []}");
        Json files = reply.at("files");

        try {
            List<FileItem> items = new RestletFileUpload(new DiskFileItemFactory())
                    .parseRepresentation(representation);
            logger.debug("Begin import files:" + items);
            for (FileItem item : items) {
                if (!item.isFormField()) {
                    InputStream inputStream = item.getInputStream();

                    Path destination = Paths.get(
                            Util.getConfigProperty(STATIC_DIR) + Util.getConfigProperty(MAP_DIR) + item.getName());
                    logger.debug("Save import file:" + destination);
                    long len = Files.copy(inputStream, destination, StandardCopyOption.REPLACE_EXISTING);
                    Json f = Json.object();
                    f.set("name", item.getName());
                    f.set("size", len);
                    files.add(f);
                    install(destination);
                }
            }
        } catch (FileUploadException | IOException e) {
            logger.error(e.getMessage(), e);
        }
        exchange.getIn().setBody(reply);
    }

    private void install(Path destination) throws Exception {
        if (!destination.toString().endsWith(".zip"))
            return;
        //unzip here
        logger.debug("Unzipping file:" + destination);
        try {
            File zipFile = destination.toFile();
            String f = destination.toFile().getName();
            f = f.substring(0, f.indexOf("."));
            File destDir = new File(Util.getConfigProperty(STATIC_DIR) + Util.getConfigProperty(MAP_DIR) + f);
            if (!destDir.exists()) {
                destDir.mkdirs();
            }
            ZipUtils.unzip(destDir, zipFile);
            logger.debug("Unzipped file:" + destDir);
            //now add a reference in resources
            loadChart(f);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    public void loadChart(String chartName) throws Exception {
        try {
            File destDir = new File(
                    Util.getConfigProperty(STATIC_DIR) + Util.getConfigProperty(MAP_DIR) + chartName);
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File(destDir, "tilemapresource.xml"));

            String title = document.getRootElement().element("Title").getText();
            String scale = "250000";
            if (document.getRootElement().element("Metadata") != null) {
                scale = document.getRootElement().element("Metadata").attribute("scale").getText();
            }
            double maxRes = 0.0;
            double minRes = Double.MAX_VALUE;
            int maxZoom = 0;
            int minZoom = 99;
            Element tileSets = document.getRootElement().element("TileSets");
            for (Object o : tileSets.elements("TileSet")) {
                Element e = (Element) o;
                int href = Integer.parseInt(e.attribute("href").getValue());
                maxZoom = Math.max(href, maxZoom);
                minZoom = Math.min(href, minZoom);
                double units = Double.parseDouble(e.attribute("units-per-pixel").getValue());
                maxRes = Math.max(units, maxRes);
                minRes = Math.min(units, minRes);
            }
            //now make an entry in resources
            Json resource = createChartMsg(chartName, title, scale);
            inProducer.asyncSendBody(inProducer.getDefaultEndpoint(), resource);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    private Json createChartMsg(String f, String title, String scale) {
        Json val = Json.object();
        val.set(SignalKConstants.PATH, "charts." + "urn:mrn:signalk:uuid:" + UUID.randomUUID().toString());
        Json currentChart = Json.object();
        val.set(value, currentChart);
        String time = Util.getIsoTimeString();
        time = time.substring(0, time.indexOf("."));
        currentChart.set("identifier", f);
        currentChart.set(name, title);
        currentChart.set("description", title);
        currentChart.set("tilemapUrl", "/" + Util.getConfigProperty(MAP_DIR) + f);
        try {
            int scaleInt = Integer.valueOf(scale);
            currentChart.set("scale", scaleInt);
        } catch (Exception e) {
            currentChart.set("scale", 0);
        }

        Json values = Json.array();
        values.add(val);

        Json update = Json.object();

        update.set(SignalKConstants.values, values);

        Json updates = Json.array();
        updates.add(update);
        Json msg = Json.object();
        msg.set(SignalKConstants.CONTEXT, resources);
        msg.set(SignalKConstants.PUT, updates);

        if (logger.isDebugEnabled())
            logger.debug("Created new chart msg:" + msg);
        return msg;
    }

}