com.safetys.framework.fckeditor.connector.Dispatcher.java Source code

Java tutorial

Introduction

Here is the source code for com.safetys.framework.fckeditor.connector.Dispatcher.java

Source

/*
 * FCKeditor - The text editor for Internet - http://www.fckeditor.net Copyright (C) 2004-2010 Frederico Caldeira Knabben == BEGIN LICENSE == Licensed under the terms of any of the following licenses
 * at your choice: - GNU General Public License Version 2 or later (the "GPL") http://www.gnu.org/licenses/gpl.html - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
 * http://www.gnu.org/licenses/lgpl.html - Mozilla Public License Version 1.1 or later (the "MPL") http://www.mozilla.org/MPL/MPL-1.1.html == END LICENSE ==
 */
package com.safetys.framework.fckeditor.connector;

import java.io.IOException;
import java.util.List;

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

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.safetys.framework.fckeditor.connector.exception.FolderAlreadyExistsException;
import com.safetys.framework.fckeditor.connector.exception.InvalidCurrentFolderException;
import com.safetys.framework.fckeditor.connector.exception.InvalidNewFolderNameException;
import com.safetys.framework.fckeditor.connector.exception.ReadException;
import com.safetys.framework.fckeditor.connector.exception.WriteException;
import com.safetys.framework.fckeditor.handlers.Command;
import com.safetys.framework.fckeditor.handlers.PropertiesLoader;
import com.safetys.framework.fckeditor.handlers.RequestCycleHandler;
import com.safetys.framework.fckeditor.handlers.ResourceType;
import com.safetys.framework.fckeditor.requestcycle.Context;
import com.safetys.framework.fckeditor.requestcycle.ThreadLocalData;
import com.safetys.framework.fckeditor.response.GetResponse;
import com.safetys.framework.fckeditor.response.UploadResponse;
import com.safetys.framework.fckeditor.tool.Utils;
import com.safetys.framework.fckeditor.tool.UtilsFile;
import com.safetys.framework.fckeditor.tool.UtilsResponse;

/**
 * File Browser request dispatcher. This class is the validating and managing instance between the {@link ConnectorServlet connector servlet} and the {@link Connector connector}. It receives the
 * requests, parses the parameters, validates/sanitizes them and mandates them to the connector. After the connector has processed the request, this dispatcher passes the response back to the
 * connector servlet. More over, it intercepts all {@link com.safetys.framework.fckeditor.connector.exception specified exceptions} from a connector and emits appropriate (localized) messages to the user. The
 * exceptions won't be logged, they simply indicate the connector state.
 * 
 * @version $Id: Dispatcher.java 4785 2009-12-21 20:10:28Z mosipov $
 */
public class Dispatcher {
    private static final Logger logger = LoggerFactory.getLogger(Dispatcher.class);
    private Connector connector;

    /**
     * Initializes this dispatcher. It initializes the connector internally. Called at connector servlet {@link ConnectorServlet#init() initialization}.
     * 
     * @param servletContext
     *            reference to the {@link ServletContext} in which the caller is running
     * @throws Exception
     *             if the dispatcher initialization fails due to some reason
     */
    Dispatcher(final ServletContext servletContext) throws Exception {
        // try to instantiate the Connector object
        final String className = PropertiesLoader.getConnectorImpl();
        if (Utils.isEmpty(className)) {
            Dispatcher.logger.error("Empty Connector implementation class name provided");
        } else {
            try {
                final Class<?> clazz = Class.forName(className);
                this.connector = (Connector) clazz.newInstance();
                Dispatcher.logger.info("Connector initialized to {}", className);
            } catch (final Throwable e) {
                Dispatcher.logger.error("Connector implementation {} could not be instantiated", className);
                throw new RuntimeException("Connector implementation " + className + " could not be instantiated", //$NON-NLS-1$
                        e);
            }
        }
        this.connector.init(servletContext);
    }

    /**
     * Called by the connector servlet to handle a {@code GET} request. In particular, it handles the {@link Command#GET_FOLDERS GetFolders}, {@link Command#GET_FOLDERS_AND_FILES GetFoldersAndFiles}
     * and {@link Command#CREATE_FOLDER CreateFolder} commands.
     * 
     * @param request
     *            the current request instance
     * @return the get response instance associated with this request
     */
    GetResponse doGet(final HttpServletRequest request) {
        Dispatcher.logger.debug("Entering Dispatcher#doGet");

        final Context context = ThreadLocalData.getContext();
        context.logBaseParameters();

        GetResponse getResponse = null;
        // check parameters
        if (!Command.isValidForGet(context.getCommandStr())) {
            getResponse = GetResponse.getInvalidCommandError();
        } else if (!ResourceType.isValidType(context.getTypeStr())) {
            getResponse = GetResponse.getInvalidResourceTypeError();
        } else if (!UtilsFile.isValidPath(context.getCurrentFolderStr())) {
            getResponse = GetResponse.getInvalidCurrentFolderError();
        } else {

            // in contrast to doPost the referrer has to send an explicit type
            final ResourceType type = context.getResourceType();
            final Command command = context.getCommand();

            // check permissions for user action
            if ((command.equals(Command.GET_FOLDERS) || command.equals(Command.GET_FOLDERS_AND_FILES))
                    && !RequestCycleHandler.isGetResourcesEnabled(request)) {
                getResponse = GetResponse.getGetResourcesDisabledError();
            } else if (command.equals(Command.CREATE_FOLDER)
                    && !RequestCycleHandler.isCreateFolderEnabled(request)) {
                getResponse = GetResponse.getCreateFolderDisabledError();
            } else {
                // make the connector calls, catch its exceptions and generate
                // the proper response object
                try {
                    if (command.equals(Command.CREATE_FOLDER)) {
                        final String newFolderNameStr = request.getParameter("NewFolderName");
                        Dispatcher.logger.debug("Parameter NewFolderName: {}", newFolderNameStr);
                        final String sanitizedNewFolderNameStr = UtilsFile.sanitizeFolderName(newFolderNameStr);
                        if (Utils.isEmpty(sanitizedNewFolderNameStr)) {
                            getResponse = GetResponse.getInvalidNewFolderNameError();
                        } else {
                            Dispatcher.logger.debug("Parameter NewFolderName (sanitized): {}",
                                    sanitizedNewFolderNameStr);
                            this.connector.createFolder(type, context.getCurrentFolderStr(),
                                    sanitizedNewFolderNameStr);
                            getResponse = GetResponse.getOK();
                        }
                    } else if (command.equals(Command.GET_FOLDERS)
                            || command.equals(Command.GET_FOLDERS_AND_FILES)) {
                        final String url = UtilsResponse.getUrl(RequestCycleHandler.getUserFilesPath(request), type,
                                context.getCurrentFolderStr());
                        getResponse = this.getFoldersAndOrFiles(command, type, context.getCurrentFolderStr(), url);
                    }
                } catch (final InvalidCurrentFolderException e) {
                    getResponse = GetResponse.getInvalidCurrentFolderError();
                } catch (final InvalidNewFolderNameException e) {
                    getResponse = GetResponse.getInvalidNewFolderNameError();
                } catch (final FolderAlreadyExistsException e) {
                    getResponse = GetResponse.getFolderAlreadyExistsError();
                } catch (final WriteException e) {
                    getResponse = GetResponse.getCreateFolderWriteError();
                } catch (final ReadException e) {
                    getResponse = GetResponse.getGetResourcesReadError();
                }
            }
        }

        Dispatcher.logger.debug("Exiting Dispatcher#doGet");
        return getResponse;
    }

    /**
     * Returns get response for the {@code GetFolders*} commands. This is simply a helper method.
     * 
     * @param command
     *            the current command, should be only GetFolders or GetFoldersAndFiles
     * @param the
     *            current resource type
     * @param currentFolder
     *            the current folder
     * @param constructedUrl
     *            the final URL
     * @return the get response instance associated with this request
     * @throws InvalidCurrentFolderException
     *             if the current folder name is invalid or does not exist within the underlying backend
     * @throws ReadException
     *             if the file attributes and/or folder names could not be read due to some reason
     */
    private GetResponse getFoldersAndOrFiles(final Command command, final ResourceType type,
            final String currentFolder, final String constructedUrl)
            throws InvalidCurrentFolderException, ReadException {
        final GetResponse getResponse = new GetResponse(command, type, currentFolder, constructedUrl);
        getResponse.setFolders(this.connector.getFolders(type, currentFolder));
        if (command.equals(Command.GET_FOLDERS_AND_FILES)) {
            getResponse.setFiles(this.connector.getFiles(type, currentFolder));
        }
        return getResponse;
    }

    /**
     * Called by the connector servlet to handle a {@code POST} request. In particular, it handles the {@link Command#FILE_UPLOAD FileUpload} and {@link Command#QUICK_UPLOAD QuickUpload} commands.
     * 
     * @param request
     *            the current request instance
     * @return the upload response instance associated with this request
     */
    @SuppressWarnings("unchecked")
    UploadResponse doPost(final HttpServletRequest request) {
        Dispatcher.logger.debug("Entering Dispatcher#doPost");

        final Context context = ThreadLocalData.getContext();
        context.logBaseParameters();

        UploadResponse uploadResponse = null;
        // check permissions for user actions
        if (!RequestCycleHandler.isFileUploadEnabled(request)) {
            uploadResponse = UploadResponse.getFileUploadDisabledError();
        } else if (!Command.isValidForPost(context.getCommandStr())) {
            uploadResponse = UploadResponse.getInvalidCommandError();
        } else if (!ResourceType.isValidType(context.getTypeStr())) {
            uploadResponse = UploadResponse.getInvalidResourceTypeError();
        } else if (!UtilsFile.isValidPath(context.getCurrentFolderStr())) {
            uploadResponse = UploadResponse.getInvalidCurrentFolderError();
        } else {

            // call the Connector#fileUpload
            final ResourceType type = context.getDefaultResourceType();
            final FileItemFactory factory = new DiskFileItemFactory();
            final ServletFileUpload upload = new ServletFileUpload(factory);
            try {
                final List<FileItem> items = upload.parseRequest(request);
                // We upload just one file at the same time
                final FileItem uplFile = items.get(0);
                // Some browsers transfer the entire source path not just the
                // filename
                final String fileName = FilenameUtils.getName(uplFile.getName());
                Dispatcher.logger.debug("Parameter NewFile: {}", fileName);
                // check the extension
                if (type.isDeniedExtension(FilenameUtils.getExtension(fileName))) {
                    uploadResponse = UploadResponse.getInvalidFileTypeError();
                } else if (type.equals(ResourceType.IMAGE) && PropertiesLoader.isSecureImageUploads()
                        && !UtilsFile.isImage(uplFile.getInputStream())) {
                    uploadResponse = UploadResponse.getInvalidFileTypeError();
                } else {
                    final String sanitizedFileName = UtilsFile.sanitizeFileName(fileName);
                    Dispatcher.logger.debug("Parameter NewFile (sanitized): {}", sanitizedFileName);
                    final String newFileName = this.connector.fileUpload(type, context.getCurrentFolderStr(),
                            sanitizedFileName, uplFile.getInputStream());
                    final String fileUrl = UtilsResponse.fileUrl(RequestCycleHandler.getUserFilesPath(request),
                            type, context.getCurrentFolderStr(), newFileName);

                    if (sanitizedFileName.equals(newFileName)) {
                        uploadResponse = UploadResponse.getOK(fileUrl);
                    } else {
                        uploadResponse = UploadResponse.getFileRenamedWarning(fileUrl, newFileName);
                        Dispatcher.logger.debug("Parameter NewFile (renamed): {}", newFileName);
                    }
                }

                uplFile.delete();
            } catch (final InvalidCurrentFolderException e) {
                uploadResponse = UploadResponse.getInvalidCurrentFolderError();
            } catch (final WriteException e) {
                uploadResponse = UploadResponse.getFileUploadWriteError();
            } catch (final IOException e) {
                uploadResponse = UploadResponse.getFileUploadWriteError();
            } catch (final FileUploadException e) {
                uploadResponse = UploadResponse.getFileUploadWriteError();
            }
        }

        Dispatcher.logger.debug("Exiting Dispatcher#doPost");
        return uploadResponse;
    }

}