presentation.webgui.vitroappservlet.uploadService.UploadServlet.java Source code

Java tutorial

Introduction

Here is the source code for presentation.webgui.vitroappservlet.uploadService.UploadServlet.java

Source

/*
 * #--------------------------------------------------------------------------
 * # Copyright (c) 2013 VITRO FP7 Consortium.
 * # All rights reserved. This program and the accompanying materials
 * # are made available under the terms of the GNU Lesser Public License v3.0 which accompanies this distribution, and is available at
 * # http://www.gnu.org/licenses/lgpl-3.0.html
 * #
 * # Contributors:
 * #     Antoniou Thanasis (Research Academic Computer Technology Institute)
 * #     Paolo Medagliani (Thales Communications & Security)
 * #     D. Davide Lamanna (WLAB SRL)
 * #     Alessandro Leoni (WLAB SRL)
 * #     Francesco Ficarola (WLAB SRL)
 * #     Stefano Puglia (WLAB SRL)
 * #     Panos Trakadas (Technological Educational Institute of Chalkida)
 * #     Panagiotis Karkazis (Technological Educational Institute of Chalkida)
 * #     Andrea Kropp (Selex ES)
 * #     Kiriakos Georgouleas (Hellenic Aerospace Industry)
 * #     David Ferrer Figueroa (Telefonica Investigacin y Desarrollo S.A.)
 * #
 * #--------------------------------------------------------------------------
 */
package presentation.webgui.vitroappservlet.uploadService;

import presentation.webgui.vitroappservlet.StaxHelper.SMTools;
import com.ctc.wstx.stax.WstxInputFactory;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.codehaus.stax2.XMLStreamReader2;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMInputCursor;
import presentation.webgui.vitroappservlet.uploadService.fileupload.MonitoredDiskFileItemFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.stream.XMLInputFactory;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

/**
 *
 * This class is called for the files uploading (and monitoring of the uploading).
 * Its final response is placed in an iframe inside the calling .jsp (or html). (this
 * iframe is the target in the form that uploads the files).
 * This response is actually creating invisible code, in the sense that it only
 * writes javascript so as to call a javascript function in the parent (of the iframe) html (= the calling html)
 * which will update the <div></div> tag that has the id of "status". (using the doStatus() function).
 * 
 * This class is called normally once (due to the form "action" parameter). Then the doPost code calls the doFileUpload(),
 * which awaits until the file is fully uploaded and then processes it. When the doFileUpload() finishes up, it always calls the
 * sendCompleteResponse(), which makes sure that the calling .jsp will launch the killUpdate() javascript function
 * and will put some final status code and do some final tasks if necessary.
 * 
 * This class is however also called (its doPost actually) periodically (due to some Ajax code in the calling jsp upon submission of the form)
 * In this periodical calls, the doPost always launched the doStatus() method which updates the div tag in the calling jsp.
 *
 */
public class UploadServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doPost(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();

        if ("status".equals(request.getParameter("c"))) {
            if ("true".equals(request.getParameter("fin"))) {
                doStatus(request, session, response, true);
            } else {
                doStatus(request, session, response, false);
            }
        } else {
            doFileUpload(session, request, response);
        }
    }

    /**
     *
     * Needed because getParameter does not work with form enctype="multipart/form-data" (that uploads a file)
     */
    private FileItem myrequestGetParameter(ServletFileUpload upload, HttpServletRequest request,
            HashMap<String, String> myFileRequestParamsHM) {
        FileItem fileToReturn = null;
        try {
            List items = upload.parseRequest(request);
            for (Iterator i = items.iterator(); i.hasNext();) {
                FileItem fileItem = (FileItem) i.next();
                if (fileItem.isFormField()) {
                    myFileRequestParamsHM.put(fileItem.getFieldName(), fileItem.getString());
                    fileItem.delete();
                } else {
                    fileToReturn = fileItem;
                }
            }
        } catch (Exception e) {
            return fileToReturn;
        }
        return fileToReturn;
    }

    private void doFileUpload(HttpSession session, HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        String fname = "";
        HashMap<String, String> myFileRequestParamsHM = new HashMap<String, String>();

        try {
            FileUploadListener listener = new FileUploadListener(request.getContentLength());
            FileItemFactory factory = new MonitoredDiskFileItemFactory(listener);

            ServletFileUpload upload = new ServletFileUpload(factory);
            //        upload.setSizeMax(83886080); /* the unit is bytes */

            FileItem fileItem = null;
            fileItem = myrequestGetParameter(upload, request, myFileRequestParamsHM);

            String mode = myFileRequestParamsHM.get("mode");

            session.setAttribute("FILE_UPLOAD_STATS" + mode, listener.getFileUploadStats());

            boolean hasError = false;

            if (fileItem != null) {
                /**
                 * (for KML only files) ( not prefabs (collada) or icons or images)
                 */
                WstxInputFactory f = null;
                XMLStreamReader2 sr = null;
                SMInputCursor iroot = null;
                if (mode.equals("3dFile") || mode.equals("LinePlaceMarksFile")
                        || mode.equals("RoomCenterPointsFile")) {
                    f = new WstxInputFactory();
                    f.configureForConvenience();
                    // Let's configure factory 'optimally'...
                    f.setProperty(XMLInputFactory.IS_COALESCING, Boolean.FALSE);
                    f.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);

                    sr = (XMLStreamReader2) f.createXMLStreamReader(fileItem.getInputStream());
                    iroot = SMInputFactory.rootElementCursor(sr);
                    // If we needed to store some information about preceding siblings,
                    // we should enable tracking. (we need it for  mygetElementValueStaxMultiple method)
                    iroot.setElementTracking(SMInputCursor.Tracking.PARENTS);

                    iroot.getNext();
                    if (!"kml".equals(iroot.getLocalName().toLowerCase())) {
                        hasError = true;
                        listener.getFileUploadStats().setCurrentStatus("finito");
                        session.setAttribute("FILE_UPLOAD_STATS" + mode, listener.getFileUploadStats());
                        sendCompleteResponse(myFileRequestParamsHM, response, hasError,
                                "Root element not kml, as expected, but " + iroot.getLocalName());
                        return;
                    }
                }

                fname = "";
                if (mode.equals("3dFile")) {
                    if ((fileItem.getSize() / 1024) > 25096) { // with woodstox stax, file size should not be a problem. Let's put some limit however!
                        hasError = true;
                        listener.getFileUploadStats().setCurrentStatus("finito");
                        session.setAttribute("FILE_UPLOAD_STATS" + mode, listener.getFileUploadStats());
                        sendCompleteResponse(myFileRequestParamsHM, response, hasError,
                                "File is very large for XML handler to process!");
                        return;
                    }

                    fname = "";
                    String[] elementsToFollow = { "document", "name" };
                    Vector<String> resultValues = SMTools.mygetElementValueStax(iroot, elementsToFollow, 0);
                    if (resultValues != null && !resultValues.isEmpty()) {
                        fname = resultValues.elementAt(0);
                    }

                    if (!fname.equals("")) {
                        // check for kml extension and Add it if necessary!!
                        int lastdot = fname.lastIndexOf('.');
                        if (lastdot != -1) {
                            if (lastdot == 0) // if it is the first char then ignore it and add an extension anyway
                            {
                                fname += ".kml";
                            } else if (lastdot < fname.length() - 1) {
                                if (!(fname.substring(lastdot + 1).toLowerCase().equals("kml"))) {
                                    fname += ".kml";
                                }
                            } else if (lastdot == fname.length() - 1) {
                                fname += "kml";
                            }
                        } else {
                            fname += ".kml";
                        }

                        String realPath = this.getServletContext().getRealPath("/");
                        int lastslash = realPath.lastIndexOf(File.separator);
                        realPath = realPath.substring(0, lastslash);
                        // too slow
                        //FileWriter out = new FileWriter(realPath+File.separator+"KML"+File.separator+fname);
                        //document.sendToWriter(out);
                        // too slow
                        //StringWriter outString = new StringWriter();
                        //document.sendToWriter(outString);
                        //out.close();

                        // fast - do not process and store xml file, just store it.
                        File outFile = new File(realPath + File.separator + "Models" + File.separator + "Large"
                                + File.separator + fname);
                        outFile.createNewFile();
                        FileWriter tmpoutWriter = new FileWriter(outFile);
                        BufferedWriter buffWriter = new BufferedWriter(tmpoutWriter);
                        buffWriter.write(new String(fileItem.get()));
                        buffWriter.flush();
                        buffWriter.close();
                        tmpoutWriter.close();
                    } else {
                        hasError = true;
                        listener.getFileUploadStats().setCurrentStatus("finito");
                        session.setAttribute("FILE_UPLOAD_STATS" + mode, listener.getFileUploadStats());
                        sendCompleteResponse(myFileRequestParamsHM, response, hasError,
                                "No name tag found inside the KML file!");
                        return;
                    }
                } else if (mode.equals("LinePlaceMarksFile")) {
                    fname = "";
                    String[] elementsToFollow = { "document", "folder", "placemark", "point", "coordinates" };
                    Vector<String> resultValues = SMTools.mygetElementValueStax(iroot, elementsToFollow, 0);
                    if (resultValues != null && resultValues.size() < 2) {
                        hasError = true;
                        listener.getFileUploadStats().setCurrentStatus("finito");
                        session.setAttribute("FILE_UPLOAD_STATS" + mode, listener.getFileUploadStats());
                        sendCompleteResponse(myFileRequestParamsHM, response, hasError,
                                "File does not contain 2 placemarks!");
                        return;
                    }

                    for (int i = 0; (i < resultValues.size()) && (i < 2); i++) {
                        fname = fname + ":" + resultValues.elementAt(i);
                    }
                } else if (mode.equals("RoomCenterPointsFile")) {
                    fname = "";
                    // here: process PlaceMarks for rooms (centerpoints) in the building
                    String[] elementsToFollow0 = { "document", "folder", "placemark", "point", "coordinates" };
                    String[] elementsToFollow1 = { "document", "folder", "placemark", "name" };
                    // add elements to follow for room names and coordinates        
                    Vector<String[]> elementsToFollow = new Vector<String[]>();
                    elementsToFollow.add(elementsToFollow0);
                    elementsToFollow.add(elementsToFollow1);
                    Vector<Vector<String>> resultValues = new Vector<Vector<String>>();
                    SMTools.mygetMultipleElementValuesStax(iroot, elementsToFollow, resultValues);

                    Vector<String> resultValuesForCoords = resultValues.elementAt(0);
                    Vector<String> resultValuesForNames = resultValues.elementAt(1);

                    if (resultValuesForCoords == null || resultValuesForCoords.size() == 0
                            || resultValuesForNames == null || resultValuesForCoords.size() == 0
                            || resultValuesForCoords.size() != resultValuesForNames.size()) {
                        hasError = true;
                        listener.getFileUploadStats().setCurrentStatus("finito");
                        session.setAttribute("FILE_UPLOAD_STATS" + mode, listener.getFileUploadStats());
                        sendCompleteResponse(myFileRequestParamsHM, response, hasError,
                                "File does not contain valid data for rooms!");
                        return;
                    }

                    for (int i = 0; i < resultValuesForNames.size(); i++) {
                        // since we use ;  and ':' to seperate rooms, we replace the comma's in the rooms' names.
                        if (resultValuesForNames.elementAt(i).indexOf(';') >= 0
                                || resultValuesForNames.elementAt(i).indexOf(':') >= 0) {
                            String tmp = new String(resultValuesForNames.elementAt(i));
                            tmp.replace(';', ' ');
                            tmp.replace(':', ' ');
                            resultValuesForNames.set(i, tmp);
                        }
                        fname = fname + ";" + resultValuesForNames.elementAt(i) + ":"
                                + resultValuesForCoords.elementAt(i);
                    }

                } else if (mode.equals("DefaultIconfile") || mode.equals("DefaultPrefabfile")
                        || mode.equals("SpecialValueIconfile") || mode.equals("SpecialValuePrefabfile")
                        || mode.equals("NumericRangeIconfile") || mode.equals("NumericRangePrefabfile")) {
                    fname = "";
                    if ((fileItem.getSize() / 1024) > 10096) { // no more than 10 Mbs of size for small prefabs or icons
                        hasError = true;
                        listener.getFileUploadStats().setCurrentStatus("finito");
                        session.setAttribute("FILE_UPLOAD_STATS" + mode, listener.getFileUploadStats());
                        sendCompleteResponse(myFileRequestParamsHM, response, hasError, "File is very large!");
                        return;
                    }
                    fname = fileItem.getName();
                    if (!fname.equals("")) {
                        String realPath = this.getServletContext().getRealPath("/");
                        int lastslash = realPath.lastIndexOf(File.separator);
                        realPath = realPath.substring(0, lastslash);

                        File outFile = new File(realPath + File.separator + "Models" + File.separator + "Media"
                                + File.separator + fname);
                        outFile.createNewFile();
                        /*
                        FileWriter tmpoutWriter = new FileWriter(outFile);
                        BufferedWriter buffWriter = new BufferedWriter(tmpoutWriter);                      
                        buffWriter.write(new String(fileItem.get()));
                        buffWriter.flush();
                        buffWriter.close();
                        tmpoutWriter.close();
                        */
                        fileItem.write(outFile);
                    } else {
                        hasError = true;
                        listener.getFileUploadStats().setCurrentStatus("finito");
                        session.setAttribute("FILE_UPLOAD_STATS" + mode, listener.getFileUploadStats());
                        sendCompleteResponse(myFileRequestParamsHM, response, hasError,
                                "No valid name for uploaded file!");
                        return;
                    }
                }

                fileItem.delete();
            }

            if (!hasError) {
                sendCompleteResponse(myFileRequestParamsHM, response, hasError, fname);
            } else {
                hasError = true;
                sendCompleteResponse(myFileRequestParamsHM, response, hasError,
                        "Could not process uploaded file. Please see log for details.");
            }
        } catch (Exception e) {
            boolean hasError = true;
            sendCompleteResponse(myFileRequestParamsHM, response, hasError, "::" + fname + "::" + e.getMessage());
        }
    }

    private void doStatus(HttpServletRequest request, HttpSession session, HttpServletResponse response,
            boolean isFinalCall) throws IOException {

        // Make sure the status response is not cached by the browser
        response.addHeader("Expires", "0");
        response.addHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.addHeader("Pragma", "no-cache");

        // the doStatus is ALWAYS called by normal post (not multipart), so the following should work!
        String mode = request.getParameter("mode");

        FileUploadListener.FileUploadStats fileUploadStats = (FileUploadListener.FileUploadStats) session
                .getAttribute("FILE_UPLOAD_STATS" + mode);
        if (fileUploadStats == null || fileUploadStats.getCurrentStatus().equals("finito"))
            return;

        if (fileUploadStats != null) {
            long bytesProcessed = fileUploadStats.getBytesRead();
            long sizeTotal = fileUploadStats.getTotalSize();
            long percentComplete = (long) Math.floor(((double) bytesProcessed / (double) sizeTotal) * 100.0);
            long timeInSeconds = fileUploadStats.getElapsedTimeInSeconds();
            double uploadRate = bytesProcessed / (timeInSeconds + 0.00001);
            double estimatedRuntime = sizeTotal / (uploadRate + 0.00001);

            response.getWriter().println("<b>Upload Status:</b><br/>");

            if (fileUploadStats.getBytesRead() < fileUploadStats.getTotalSize()) {
                response.getWriter().println("<div class=\"prog-border\"><div class=\"prog-bar\" style=\"width: "
                        + percentComplete + "%;\"></div></div>");
                response.getWriter().println("Uploaded: " + bytesProcessed + " out of " + sizeTotal + " bytes ("
                        + percentComplete + "%) " + (long) Math.round(uploadRate / 1024) + " Kbs <br/>");
                response.getWriter()
                        .println("Runtime: " + formatTime(timeInSeconds) + " out of " + formatTime(estimatedRuntime)
                                + " " + formatTime(estimatedRuntime - timeInSeconds) + " remaining <br/>");
            } else {
                response.getWriter()
                        .println("Uploaded: " + bytesProcessed + " out of " + sizeTotal + " bytes<br/>");
                response.getWriter().println("Complete.<br/>");
            }
        }

        if (fileUploadStats != null && fileUploadStats.getBytesRead() == fileUploadStats.getTotalSize()) {
            response.getWriter().println("<b>Upload complete.</b>");
            response.getWriter().println("<br/><b>Stand by while processing the uploaded file...</b>");
            //response.getWriter().println("<iframe id=\"tmp\"  style='display: none'>"+
            //                             "<html><body onload='window.parent.killPeriodicUpdate('"+mode+"')'></body></html></iframe>"); // <-- does not work!

            if (isFinalCall) {
                response.getWriter().println("<b>Done!</b>");
                fileUploadStats.setTotalSize(0);
                fileUploadStats.setBytesRead(0);
                fileUploadStats.setCurrentStatus("finito");
                session.setAttribute("FILE_UPLOAD_STATS" + mode, fileUploadStats);
            }
        }

    }

    private void sendCompleteResponse(HashMap<String, String> myFileRequestParamsHM, HttpServletResponse response,
            boolean isErrorStateflag, String message) throws IOException {
        String mode = myFileRequestParamsHM.get("mode");

        String statusdiv = myFileRequestParamsHM.get("statusdiv");
        String buttonid = myFileRequestParamsHM.get("buttonid");

        if (isErrorStateflag) {
            response.getOutputStream()
                    .print("<html><head><script type='text/javascript'>function killUpdateFinal" + mode
                            + "() { window.parent.killUpdateFinal('" + mode + "','" + statusdiv + "','" + buttonid
                            + "','" + message + "'); }</script></head><body onload='killUpdateFinal" + mode
                            + "()'></body></html>");
        } else {
            response.getOutputStream()
                    .print("<html><head><script type='text/javascript'>function killUpdateFinal" + mode
                            + "() { window.parent.killUpdateFinal('" + mode + "','" + statusdiv + "','" + buttonid
                            + "', ''); window.parent.updateFileUploadTasks('" + mode + "','" + statusdiv + "','"
                            + buttonid + "','" + message + "'); }</script></head><body onload='killUpdateFinal"
                            + mode + "()'></body></html>");
        }
    }

    private String formatTime(double timeInSeconds) {
        long seconds = (long) Math.floor(timeInSeconds);
        long minutes = (long) Math.floor(timeInSeconds / 60.0);
        long hours = (long) Math.floor(minutes / 60.0);

        if (hours != 0) {
            return hours + "hours " + (minutes % 60) + "minutes " + (seconds % 60) + "seconds";
        } else if (minutes % 60 != 0) {
            return (minutes % 60) + "minutes " + (seconds % 60) + "seconds";
        } else {
            return (seconds % 60) + " seconds";
        }
    }
}