com.nartex.RichFileManager.java Source code

Java tutorial

Introduction

Here is the source code for com.nartex.RichFileManager.java

Source

/*
 *   Filemanager.java utility class for for filemanager.jsp
 *
 *   @license   MIT License
 *   @author      Dick Toussaint <d.tricky@gmail.com>
 *   @copyright   Authors
 */
package com.nartex;

import java.awt.Dimension;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * 
 * 
 * 
 * CHANGES 
 * August 2016
 * - using {@link Path} instead of {@link File} methods
 * - added mode replace
 * - added interface
 * - adapted download to new two-step mode
 * - optional indirection methods cleanPreview and getPreviewFolder to allow for URL-mapping  
 * 
 * @author gkallidis
 *
 */
public class RichFileManager extends AbstractFM implements FileManagerI {

    /**
     * 
     * @param servletContext
     * @param request
     * @throws IOException 
     */

    public RichFileManager(ServletContext servletContext, HttpServletRequest request) throws IOException {

        super(servletContext, request);

    }

    @Override
    public JSONObject getInfo() throws JSONException {
        this.item = new HashMap<String, Object>();
        this.item.put("properties", this.properties);
        this.getFileInfo("", false);
        JSONObject array = new JSONObject();

        try {
            array.put("Path", this.get.get("path"));
            array.put("Filename", this.item.get("filename"));
            array.put("File Type", this.item.get("filetype"));
            array.put("Properties", this.item.get("properties"));
            array.put("Error", "");
            array.put("Code", 0);
        } catch (Exception e) {
            this.error("JSONObject error");
        }
        return array;
    }

    @Override
    public void preview(HttpServletRequest request, HttpServletResponse resp) {

        Path file = this.documentRoot.resolve(cleanPreview(this.get.get("path")));
        boolean thumbnail = false;
        String paramThumbs = request.getParameter("thumbnail");
        if (paramThumbs != null && paramThumbs.equals("true")) {
            thumbnail = true;
        }
        long size = 0;
        try {
            size = Files.size(file);
        } catch (IOException e) {
            this.error(sprintf(lang("INVALID_DIRECTORY_OR_FILE"), file.toFile().getName()));
        }

        if (this.get.get("path") != null && Files.exists(file)) {
            resp.setHeader("Content-type", "image/" + getFileExtension(file.toFile().getName())); // octet-stream" + getFileExtension(file.toFile().getName()));
            resp.setHeader("Content-Transfer-Encoding", "Binary");
            resp.setHeader("Content-length", "" + size);
            resp.setHeader("Content-Disposition",
                    "inline; filename=\"" + getFileBaseName(file.toFile().getName()) + "\"");
            // handle caching
            resp.setHeader("Pragma", "no-cache");
            resp.setHeader("Expires", "0");
            resp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
            readSmallFile(resp, file);
        } else {
            error(sprintf(lang("FILE_DOES_NOT_EXIST"), this.get.get("path")));
        }
    }

    // expect small filesw
    protected void readSmallFile(HttpServletResponse resp, Path file) {
        OutputStream os = null;
        try {
            os = resp.getOutputStream();
            os.write(Files.readAllBytes(file));
        } catch (Exception e) {
            this.error(sprintf(lang("INVALID_DIRECTORY_OR_FILE"), file.toFile().getName()));
        } finally {
            try {
                if (os != null)
                    os.close();
            } catch (Exception e2) {
            }
        }
    }

    @Override
    public JSONObject getFolder(HttpServletRequest request) throws JSONException, IOException {
        JSONObject array = null;

        boolean showThumbs = false;
        String paramshowThumbs = request.getParameter("showThumbs");
        if (paramshowThumbs != null) {
            showThumbs = true;
        }
        Path root = documentRoot.resolve(this.get.get("path"));
        log.debug("path absolute:" + root.toAbsolutePath());
        Path docDir = documentRoot.resolve(this.get.get("path")).toRealPath(LinkOption.NOFOLLOW_LINKS);
        File dir = docDir.toFile(); //new File(documentRoot + this.get.get("path"));

        File file = null;
        if (!dir.isDirectory()) {
            this.error(sprintf(lang("DIRECTORY_NOT_EXIST"), this.get.get("path")));
        } else {
            if (!dir.canRead()) {
                this.error(sprintf(lang("UNABLE_TO_OPEN_DIRECTORY"), this.get.get("path")));
            } else {
                array = new JSONObject();
                String[] files = dir.list();
                JSONObject data = null;
                JSONObject props = null;
                for (int i = 0; i < files.length; i++) {
                    data = new JSONObject();
                    props = new JSONObject();
                    file = docDir.resolve(files[i]).toFile();
                    //new File(documentRoot + this.get.get("path") + files[i]);
                    if (file.isDirectory() && !contains(config.getProperty("unallowed_dirs"), files[i])) {
                        try {
                            props.put("Date Created", (String) null);
                            props.put("Date Modified", (String) null);
                            props.put("Height", (String) null);
                            props.put("Width", (String) null);
                            props.put("Size", (String) null);
                            data.put("Path", this.get.get("path") + files[i] + "/");
                            data.put("Filename", files[i]);
                            data.put("File Type", "dir");
                            data.put("Thumbnail",
                                    config.getProperty("icons-path") + config.getProperty("icons-directory"));
                            data.put("Error", "");
                            data.put("Code", 0);
                            data.put("Properties", props);

                            array.put(this.get.get("path") + files[i] + "/", data);
                        } catch (Exception e) {
                            this.error("JSONObject error");
                        }
                    } else if (file.canRead() && (!contains(config.getProperty("unallowed_files"), files[i]))) {
                        this.item = new HashMap<String, Object>();
                        this.item.put("properties", this.properties);
                        this.getFileInfo(this.get.get("path") + files[i], showThumbs);

                        //if (this.params.get("type") == null || (this.params.get("type") != null && (!this.params.get("type").equals("Image") || checkImageType()))) {
                        if (this.params.get("type") == null
                                || (this.params.get("type") != null && ((!this.params.get("type").equals("Image")
                                        && !this.params.get("type").equals("Flash")) || checkImageType()
                                        || checkFlashType()))) {
                            try {
                                //data.put("Path", this.get.get("path") + files[i]);
                                data.put("Path", this.item.get("path"));
                                data.put("Filename", this.item.get("filename"));
                                data.put("File Type", this.item.get("filetype"));
                                data.put("Properties", this.item.get("properties"));
                                data.put("Error", "");
                                data.put("Code", 0);
                                log.debug("data now :" + data.toString());

                                array.put(this.get.get("path") + files[i], data);
                            } catch (Exception e) {
                                this.error("JSONObject error");
                            }
                        }
                    } else {
                        log.warn("not allowed file or dir:" + files[i]);
                    }
                }
            }
        }
        log.debug("array size ready:" + ((array != null) ? array.toString() : ""));
        return array;
    }

    protected void getFileInfo(String path, boolean thumbs) throws JSONException {
        String pathTmp = path;
        if ("".equals(pathTmp)) {
            pathTmp = this.get.get("path");
        }
        String[] tmp = pathTmp.split("/");
        File file = this.documentRoot.resolve(cleanPreview(pathTmp)).toFile();
        this.item = new HashMap<String, Object>();
        String fileName = tmp[tmp.length - 1];
        this.item.put("filename", fileName);
        if (file.isFile()) {
            this.item.put("filetype", fileName.substring(fileName.lastIndexOf(".") + 1));
        } else {
            this.item.put("filetype", "dir");
        }
        this.item.put("filemtime", "" + file.lastModified());
        this.item.put("filectime", "" + file.lastModified());

        this.item.put("path", config.getProperty("icons-path") + "/" + config.getProperty("icons-default"));

        JSONObject props = new JSONObject();
        if (file.isDirectory()) {

            this.item.put("path", config.getProperty("icons-path") + config.getProperty("icons-directory"));

        } else if (isImage(pathTmp)) {

            String imagePath = getPreviewFolder() + cleanPreview(pathTmp);
            if (thumbs) { // TODO not yet implemented
                this.item.put("path", imagePath);
            } else {
                this.item.put("path", imagePath);
            }
            Dimension imgData = getImageSize(documentRoot.resolve(pathTmp).toString());
            props.put("Height", "" + imgData.height);
            props.put("Width", "" + imgData.width);
            props.put("Size", "" + file.length());
        } else {
            File icon = fileManagerRoot.resolve(config.getProperty("icons-path"))
                    .resolve(((String) this.item.get("filetype")).toLowerCase() + ".png").toFile();
            if (icon.exists()) {
                this.item.put("preview", config.getProperty("icons-path")
                        + ((String) this.item.get("filetype")).toLowerCase() + ".png");
                props.put("Size", "" + file.length());
            }
        }

        props.put("Date Modified", dateFormat.format(new Date(new Long((String) this.item.get("filemtime")))));
        this.item.put("properties", props);
    }

    /* (non-Javadoc)
     * @see com.nartex.FileManagerI#download(javax.servlet.http.HttpServletResponse)
     */
    @Override
    public JSONObject download(HttpServletRequest request, HttpServletResponse resp) {
        File file = this.documentRoot.resolve(cleanPreview(this.get.get("path"))).toFile();
        if (this.get.get("path") != null && file.exists()) {

            if (request.getParameter("force") == null || !request.getParameter("force").equals("true")) {
                JSONObject info = new JSONObject();
                try {
                    info.put("Error", "");
                    info.put("Code", 0);
                    info.put("Path", this.get.get("path").toString());
                } catch (Exception e) {
                    log("error:" + e.getMessage());
                    this.error("JSONObject error");
                }
                return info;
            }

            resp.setHeader("Content-Description", "File Transfer");
            //resp.setHeader("Content-Type", "application/force-download");
            //resp.setHeader("Content-Disposition", "inline;filename=\"" + documentRoot.resolve(this.get.get("path")).toString() + "\"");
            resp.setHeader("Content-Transfer-Encoding", "Binary");
            resp.setHeader("Content-Length", "" + file.length());
            resp.setHeader("Content-Type", "application/octet-stream");
            resp.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
            // handle caching
            resp.setHeader("Pragma", "public");
            resp.setHeader("Expires", "0");
            resp.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
            this.error = null;
            readFile(resp, file);
            log("file downloaded \"" + file.getAbsolutePath() + "\"");
        } else {
            this.error(sprintf(lang("FILE_DOES_NOT_EXIST"), this.get.get("path")));
        }
        return getError();
    }

    @Override
    public JSONObject add() {
        JSONObject fileInfo = new JSONObject();
        Iterator<FileItem> it = this.files.iterator();
        String mode = "";
        String currentPath = "";
        boolean error = false;
        long size = 0;
        if (!it.hasNext()) {
            fileInfo = this.uploadError(lang("INVALID_FILE_UPLOAD"));
        } else {
            String allowed[] = { ".", "-" };
            String fileName = "";
            FileItem targetItem = null;
            try {
                while (it.hasNext()) {
                    FileItem item = it.next();
                    if (item.isFormField()) {
                        if (item.getFieldName().equals("mode")) {
                            mode = item.getString();
                            // v1.0.6 renamed mode add to upload
                            if (!mode.equals("upload") && !mode.equals("add") && !mode.equals("replace")) {
                                //this.error(lang("INVALID_FILE_UPLOAD"));
                            }
                        } else if (item.getFieldName().equals("currentpath")) {
                            currentPath = item.getString();
                        } else if (item.getFieldName().equals("newfilepath")) {
                            currentPath = item.getString();
                        }
                    } else if (item.getFieldName().equals("files")) { // replace
                        //replace= true;
                        size = item.getSize();
                        targetItem = item;
                        // v1.0.6 renamed mode add to upload
                        if (mode.equals("add") || mode.equals("upload")) {
                            fileName = item.getName();
                            // set fileName
                        }
                    } else if (item.getFieldName().equals("newfile")) {
                        fileName = item.getName();
                        // strip possible directory (IE)
                        int pos = fileName.lastIndexOf(File.separator);
                        if (pos > 0) {
                            fileName = fileName.substring(pos + 1);
                        }
                        size = item.getSize();
                        targetItem = item;
                    }
                }
                if (!error) {
                    if (mode.equals("replace")) {
                        String tmp[] = currentPath.split("/");
                        fileName = tmp[tmp.length - 1];
                        int pos = fileName.lastIndexOf(File.separator);
                        if (pos > 0)
                            fileName = fileName.substring(pos + 1);
                        if (fileName != null) {
                            currentPath = currentPath.replace(fileName, "");
                            currentPath = currentPath.replace("//", "/");
                        }
                    } else {
                        if (!isImage(fileName) && (config.getProperty("upload-imagesonly") != null
                                && config.getProperty("upload-imagesonly").equals("true")
                                || this.params.get("type") != null && this.params.get("type").equals("Image"))) {
                            fileInfo = this.uploadError(lang("UPLOAD_IMAGES_ONLY"));
                            error = true;
                        }
                        LinkedHashMap<String, String> strList = new LinkedHashMap<String, String>();
                        strList.put("fileName", fileName);
                        fileName = cleanString(strList, allowed).get("fileName");
                    }
                    long maxSize = 0;
                    if (config.getProperty("upload-size") != null) {
                        maxSize = Integer.parseInt(config.getProperty("upload-size"));
                        if (maxSize != 0 && size > (maxSize * 1024 * 1024)) {
                            fileInfo = this.uploadError(sprintf(lang("UPLOAD_FILES_SMALLER_THAN"), maxSize + "Mb"));
                            error = true;
                        }
                    }
                    if (!error) {
                        currentPath = cleanPreview(currentPath.replaceFirst("^/", ""));// relative
                        Path path = currentPath.equals("") ? this.documentRoot
                                : this.documentRoot.resolve(currentPath);
                        if (config.getProperty("upload-overwrite").toLowerCase().equals("false")) {
                            fileName = this.checkFilename(path.toString(), fileName, 0);
                        }
                        if (mode.equals("replace")) {
                            File saveTo = path.resolve(fileName).toFile();
                            targetItem.write(saveTo);
                            log.info("saved " + saveTo);
                        } else {
                            fileName = fileName.replace("//", "/").replaceFirst("^/", "");// relative
                            File saveTo = path.resolve(fileName).toFile();
                            targetItem.write(saveTo);
                            log.info("saved " + saveTo);
                        }
                        fileInfo.put("Path", getPreviewFolder() + currentPath);
                        fileInfo.put("Name", fileName);
                        fileInfo.put("Error", "");
                        fileInfo.put("Code", 0);
                    }
                }
            } catch (Exception e) {
                fileInfo = this.uploadError(lang("INVALID_FILE_UPLOAD"));
            }
        }
        return fileInfo;
    }

    private JSONObject uploadError(String msg) {
        JSONObject errorInfo = new JSONObject();
        try {
            errorInfo.put("Code", "-1");
            JSONArray filesError = new JSONArray();
            filesError.put(msg);
            errorInfo.put("files", filesError);
        } catch (Exception e) {
            this.error("JSONObject error");
        }
        log.error(msg);
        this.error = errorInfo;
        return error;
    }

    @Override
    public JSONObject moveItem() {
        String itemName = this.get.get("old");
        boolean error = false;
        JSONObject array = null;
        String tmp[] = itemName.split("/");
        String filename = tmp[tmp.length - 1];
        int pos = itemName.lastIndexOf("/");

        Path fileTo = null;
        if (pos > 0 && itemName.contains("..")) {
            String path = itemName.substring(0, pos + 1);
            fileTo = this.documentRoot.resolve(cleanPreview(path)); // from subfolder, folder could be .. check later in root
        } else {
            fileTo = this.documentRoot;
        }
        //String root =  this.get.get("root"); // slash at beginning and end
        String folder = this.get.get("new");
        if (folder.trim().startsWith("/")) { // absolute path is not allowed, this is then just root folder
            folder = folder.trim().replaceFirst("/", "");
        }
        Path fileFrom = null;

        try {
            fileFrom = this.documentRoot.resolve(cleanPreview(itemName));
            fileTo = fileTo.resolve(folder).resolve(filename).normalize();

            if (!fileTo.toString().contains(this.documentRoot.toString())) {
                log.error("file is not in root folder " + this.documentRoot + " but " + fileTo);
                return this.error(sprintf(lang("ERROR_RENAMING_FILE"), filename + "#" + this.get.get("new")));
            }
            log.info("moving file from " + this.documentRoot.resolve(cleanPreview(this.get.get("old"))) + " to "
                    + this.documentRoot.resolve(folder).resolve(filename));
            if (Files.exists(fileTo)) {
                if (Files.isDirectory(fileTo)) {
                    this.error(sprintf(lang("DIRECTORY_ALREADY_EXISTS"),
                            this.documentRoot.resolve(folder).resolve(filename).toString()));
                    error = true;
                } else { // fileTo.isFile
                    this.error(sprintf(lang("FILE_ALREADY_EXISTS"), filename));
                    error = true;
                }
            } else {
                Files.move(fileFrom, fileTo);
            }
        } catch (Exception e) {
            if (Files.isDirectory(fileFrom)) {
                this.error(sprintf(lang("ERROR_RENAMING_DIRECTORY"), filename + "#" + this.get.get("new")));
            } else {
                this.error(sprintf(lang("ERROR_RENAMING_FILE"), filename + "#" + this.get.get("new")));
            }
            error = true;
        }
        if (!error) {
            array = new JSONObject();
            try {
                folder = folder.replace("..", "");// if its an allowed up mpvement
                array.put("Error", "");
                array.put("Code", 0);
                array.put("Old Path", itemName);
                array.put("Old Name", filename);
                array.put("New Path", getPreviewFolder() + folder);
                array.put("New Name", filename);
            } catch (Exception e) {
                this.error("JSONObject error");
            }
        }
        return array;
    }

    @Override
    public JSONObject rename() {
        String relativePath = cleanPreview(this.get.get("old"));
        if (relativePath.endsWith("/")) {
            //this.get.put("old", (this.get.get("old")).substring(0, ((this.get.get("old")).length() - 1)));
            relativePath = relativePath.replaceFirst("/$", "");
        }
        boolean error = false;
        JSONObject array = null;
        String tmp[] = relativePath.split("/");
        String filename = tmp[tmp.length - 1];
        int pos = relativePath.lastIndexOf("/");
        String path = relativePath.substring(0, pos + 1);
        Path fileFrom = null;
        Path fileTo = null;
        try {
            fileFrom = this.documentRoot.resolve(path).resolve(filename);
            fileTo = this.documentRoot.resolve(path).resolve(cleanPreview(this.get.get("new")));
            if (fileTo.toFile().exists()) {
                if (fileTo.toFile().isDirectory()) {
                    this.error(sprintf(lang("DIRECTORY_ALREADY_EXISTS"), this.get.get("new")));
                    error = true;
                } else { // fileTo.isFile
                    // Files.isSameFile(fileFrom, fileTo);
                    this.error(sprintf(lang("FILE_ALREADY_EXISTS"), this.get.get("new")));
                    error = true;
                }
            } else {
                //if (fileFrom.equals(fileTo));
                Files.move(fileFrom, fileTo, StandardCopyOption.REPLACE_EXISTING);
            }
        } catch (Exception e) {
            if (fileFrom.toFile().isDirectory()) {
                this.error(sprintf(lang("ERROR_RENAMING_DIRECTORY"), filename + "#" + this.get.get("new")), e);
            } else {
                this.error(sprintf(lang("ERROR_RENAMING_FILE"), filename + "#" + this.get.get("new")), e);
            }
            error = true;
        }
        if (!error) {
            array = new JSONObject();
            try {
                array.put("Error", "");
                array.put("Code", 0);
                array.put("Old Path", this.get.get("old"));
                array.put("Old Name", filename);
                array.put("New Path", getPreviewFolder() + path + this.get.get("new"));
                array.put("New Name", this.get.get("new"));
            } catch (Exception e) {
                this.error("JSONObject error");
            }
        }
        return array;
    }

    @Override
    public JSONObject delete() {
        JSONObject array = null;
        String targetPath = cleanPreview(this.get.get("path"));
        File file = this.documentRoot.resolve(targetPath).toFile();
        //new File(this.documentRoot + this.get.get("path"));
        if (file.isDirectory()) {
            array = new JSONObject();
            this.unlinkRecursive(this.documentRoot.resolve(targetPath).toFile(), true);
            try {
                array.put("Error", "");
                array.put("Code", 0);
                array.put("Path", this.get.get("path"));
            } catch (Exception e) {
                this.error("JSONObject error");
            }
        } else if (file.exists()) {
            array = new JSONObject();
            if (file.delete()) {
                try {
                    array.put("Error", "");
                    array.put("Code", 0);
                    array.put("Path", this.get.get("path"));
                } catch (Exception e) {
                    this.error("JSONObject error");
                }
            } else
                this.error(sprintf(lang("ERROR_DELETING FILE"), this.get.get("path")));
            return array;
        } else {
            this.error(lang("INVALID_DIRECTORY_OR_FILE"));
        }
        return array;
    }

    @Override
    public JSONObject addFolder() {
        JSONObject array = null;
        String allowed[] = { "-", " " };
        LinkedHashMap<String, String> strList = new LinkedHashMap<String, String>();
        strList.put("fileName", this.get.get("name"));
        String filename = cleanString(strList, allowed).get("fileName");
        if (filename.length() == 0) // the name existed of only special
            // characters
            this.error(sprintf(lang("UNABLE_TO_CREATE_DIRECTORY"), this.get.get("name")));
        else {
            String targetPath = cleanPreview(this.get.get("path"));
            File file = this.documentRoot.resolve(targetPath).resolve(filename).toFile();
            if (file.isDirectory()) {
                this.error(sprintf(lang("DIRECTORY_ALREADY_EXISTS"), filename));
            } else if (!file.mkdir()) {
                this.error(sprintf(lang("UNABLE_TO_CREATE_DIRECTORY"), filename));
            } else {
                try {
                    String parent = (this.get.get("path").equals("")) ? "/" : this.get.get("path");
                    array = new JSONObject();
                    array.put("Parent", parent);
                    array.put("Name", filename);
                    array.put("Error", "");
                    array.put("Code", 0);
                } catch (Exception e) {
                    this.error("JSONObject error");
                }
            }
        }
        return array;
    }

    @Override
    public void loadLanguageFile() {

        // we load langCode var passed into URL if present
        // else, we use default configuration var
        if (language == null || reload) {
            String lang = "";
            if (params.get("langCode") != null)
                lang = this.params.get("langCode");
            else
                lang = config.getProperty("culture");
            BufferedReader br = null;
            InputStreamReader isr = null;
            String text;
            StringBuffer contents = new StringBuffer();
            try {
                isr = new InputStreamReader(new FileInputStream(
                        this.fileManagerRoot.resolve("scripts/languages/").resolve(lang + ".json").toString()),
                        "UTF-8");
                br = new BufferedReader(isr);
                while ((text = br.readLine()) != null)
                    contents.append(text);
                language = new JSONObject(contents.toString());
            } catch (Exception e) {
                this.error("Fatal error: Language file not found.");
            } finally {
                try {
                    if (br != null)
                        br.close();
                } catch (Exception e2) {
                }
                try {
                    if (isr != null)
                        isr.close();
                } catch (Exception e2) {
                }
            }
        }
    }

    /**
     * constructs mapping from property preview.
     * 
     * Suspended, due to https://github.com/servocoder/RichFilemanager/issues/27
     * 
     */
    protected String getPreviewFolder() {
        // TODO   not yet implemented
        //if (directURL) { } 
        return "";
    }

    /**
     * clean mapping  
     * @param filecontextpath
     * @return filecontextpath
     */
    protected String cleanPreview(String filecontextpath) {
        // TODO    not yet implemented
        //if (directURL) { }    
        return filecontextpath;
    }

}