org.elfinder.servlets.AbstractConnectorServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.elfinder.servlets.AbstractConnectorServlet.java

Source

/*
 * FCKeditor - The text editor for internet Copyright (C) 2003-2005 Frederico Caldeira Knabben Licensed under the terms of the GNU Lesser General Public
 * License: http://www.opensource.org/licenses/lgpl-license.php For further information visit: http://www.fckeditor.net/ File Name: ConnectorServlet.java Java
 * Connector for Resource Manager class. Version: 2.3 Modified: 2005-08-11 16:29:00 File Authors: Simone Chiaretta (simo@users.sourceforge.net)
 */

package org.elfinder.servlets;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.elfinder.servlets.commands.AbstractCommand;
import org.elfinder.servlets.commands.ContentCommand;
import org.elfinder.servlets.commands.OpenCommand;
import org.elfinder.servlets.config.AbstractConnectorConfig;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * @author Antoine Walter (www.anw.fr)
 * @date 29 aug. 2011
 * @version $Id$
 * @license BSD
 */

/**
 * This abstract servlet acts as controler:<br>
 * - receives requests from ElFinder client<br>
 * - retrieves appropriate configuration<br>
 * - instanciates command implementation and executes it<br>
 * - returns json or HTML response<br>
 * <br>
 * <br>
 * This class is *abstract*, you have to implement prepareConfig() so that the servlet will fit to your needs.<br>
 * This way, a single servlet can use multiple configurations and be used as backend of multiple ElFinder clients.<br>
 * <br>
 * Commands are implemented into the same package, in example: org.elfinder.servlets.commands.MkdirCommand<br>
 * Each command can be extended and overriden for specific needs. All you have to do is to create an new class with the following naming convention:<br>
 * => org.elfinder.servlets.commands.MkdirCommandOverride overrides org.elfinder.servlets.commands.MkdirCommand<br>
 */
public abstract class AbstractConnectorServlet extends HttpServlet {

    private static Logger logger = Logger.getLogger(AbstractConnectorServlet.class);

    /**
     * JSON response.
     */
    private JSONObject json;

    /**
     * Parameters read from request.
     */
    private Map<String, Object> requestParams;

    /**
     * Files read from request.
     */
    private List<FileItemStream> listFiles;

    /**
     * Files data read from request.
     */
    private List<ByteArrayOutputStream> listFileStreams;

    /**
     * This function must be implemented to return appropriate configuration.<br>
     * A single servlet can manage multiple configurations and be used as backend of multiple ElFinder clients.
     * @param request
     * @return
     * @throws Exception
     */
    protected abstract AbstractConnectorConfig prepareConfig(HttpServletRequest request) throws Exception;

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Processing a new request from ElFinder client.
     * @param request
     * @param response
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) {
        if (logger.isDebugEnabled()) {
            logger.debug("processing request: " + request.getRequestURI() + request.getQueryString());
        }

        // important: set encoding BEFORE writing anything in the response...
        response.setCharacterEncoding("UTF-8");
        //HttpUtils.noCache(response);

        // parse request parameters and files...
        parseRequest(request, response);

        json = new JSONObject();

        try {
            // set configuration
            AbstractConnectorConfig config = prepareConfig(request);
            if (config == null) {
                throw new Exception("Configuration problem");
            }

            if (!config.getAuthenticator().isAllowed(request)) {
                putResponse("error", "Access denied.");
                output(response, false, json, response.getWriter());
            }

            try {
                // prepare command and run
                AbstractCommand command = prepareCommand((String) requestParams.get("cmd"), request, response,
                        config);

                try {
                    command.execute();
                } catch (ConnectorException e) {
                    logger.warn("command returned an error", e);
                    putResponse("error", e.getMessage());
                }

                // append init info if needed
                if (command.mustRunInit()) {
                    try {
                        command.initCommand();
                    } catch (ConnectorException e) {
                        logger.warn("command returned an error", e);
                        putResponse("error", e.getMessage());
                    }
                }

                // output if command didn't do it
                if (!command.isResponseOutputDone()) {
                    output(response, command.isResponseTextHtml(), json, command.getResponseWriter());
                    command.setResponseOutputDone(true);
                }

            } catch (Exception e) {
                // logger.error("Unknown error", e);
                // putResponse("error", "Unknown error");

                // output the error
                // try {
                // output(response, false, json, response.getWriter());
                // } catch (Exception ee) {
                // logger.error("", ee);
                // }
            }

            // close streams
            if (listFileStreams != null) {
                for (ByteArrayOutputStream os : listFileStreams) {
                    try {
                        os.close();
                    } catch (Exception e) {
                    }
                }
            }
        } catch (Exception e) {
        }
    }

    protected static void output(HttpServletResponse response, boolean isResponseTextHtml, JSONObject json,
            PrintWriter responseWriter) {
        // encoding was already set by servlet
        if (isResponseTextHtml) {
            response.setContentType("text/html; charset=UTF-8");
        } else {
            response.setContentType("application/json; charset=UTF-8");
        }

        try {
            json.write(responseWriter);
        } catch (Exception e) {
            logger.error("", e);
        }

        AbstractCommand.closeWriter(responseWriter);
    }

    /**
     * Parse request parameters and files.
     * @param request
     * @param response
     */
    protected void parseRequest(HttpServletRequest request, HttpServletResponse response) {
        requestParams = new HashMap<String, Object>();
        listFiles = new ArrayList<FileItemStream>();
        listFileStreams = new ArrayList<ByteArrayOutputStream>();

        // Parse the request
        if (ServletFileUpload.isMultipartContent(request)) {
            // multipart request
            try {
                ServletFileUpload upload = new ServletFileUpload();
                FileItemIterator iter = upload.getItemIterator(request);

                while (iter.hasNext()) {
                    FileItemStream item = iter.next();
                    String name = item.getFieldName();
                    InputStream stream = item.openStream();
                    if (item.isFormField()) {
                        requestParams.put(name, Streams.asString(stream));
                    } else {
                        String fileName = item.getName();
                        if (fileName != null && !"".equals(fileName.trim())) {
                            listFiles.add(item);

                            ByteArrayOutputStream os = new ByteArrayOutputStream();
                            IOUtils.copy(stream, os);
                            listFileStreams.add(os);
                        }
                    }
                }
            } catch (Exception e) {
                logger.error("Unexpected error parsing multipart content", e);
            }
        } else {
            // not a multipart
            for (Object mapKey : request.getParameterMap().keySet()) {
                String mapKeyString = (String) mapKey;

                if (mapKeyString.endsWith("[]")) {
                    // multiple values
                    String values[] = request.getParameterValues(mapKeyString);
                    List<String> listeValues = new ArrayList<String>();
                    for (String value : values) {
                        listeValues.add(value);
                    }
                    requestParams.put(mapKeyString, listeValues);
                } else {
                    // single value
                    String value = request.getParameter(mapKeyString);
                    requestParams.put(mapKeyString, value);
                }
            }
        }
    }

    /**
     * Instanciate command implementation and prepare it before execution.
     * @param commandStr
     * @param request
     * @param response
     * @param config
     * @return
     */
    protected AbstractCommand prepareCommand(String commandStr, HttpServletRequest request,
            HttpServletResponse response, AbstractConnectorConfig config) {
        if (commandStr != null) {
            commandStr = commandStr.trim();
        }

        if (commandStr == null && "POST".equals(request.getMethod())) {
            putResponse("error", "Data exceeds the maximum allowed size");
        }

        if (!config.isCommandAllowed(commandStr)) {
            putResponse("error", "Permission denied");
        }

        AbstractCommand command = null;
        if (commandStr != null) {
            command = instanciateCommand(commandStr);
            if (command == null) {
                putResponse("error", "Unknown command");
            }
        } else {
            String[] current = (String[]) request.getParameterMap().get("current");
            if (current != null) {
                command = new OpenCommand();
            } else {
                command = new ContentCommand();
            }
        }

        try {
            command.setRequest(request);
            command.setResponse(response);
            command.setJson(json);
            command.setRequestParameters(requestParams);
            command.setListFiles(listFiles);
            command.setListFileStreams(listFileStreams);
            command.setConfig(config);

            command.init();
        } catch (Exception e) {
        }

        return command;
    }

    /**
     * Instanciate a command from its name.
     * @param commandName
     * @return
     */
    protected AbstractCommand instanciateCommand(String commandName) {
        AbstractCommand instance = null;
        try {
            Class<AbstractCommand> clazz = getCommandClass(commandName);
            if (clazz != null) {
                instance = clazz.newInstance();
                if (instance == null) {
                    throw new Exception("Command not found : " + commandName);
                }
            }
        } catch (Exception e) {
            // instance will be null
            logger.error("Could not instanciate connector configuration", e);
        }
        return instance;
    }

    /**
     * Get command class for a command name.
     * @param commandName
     * @return
     */
    protected Class<AbstractCommand> getCommandClass(String commandName) {
        // do we have override for command?
        Class<AbstractCommand> clazz = getCommandClassOverride(commandName);
        if (clazz == null) {
            // no override, use the default command
            clazz = getCommandClassDefault(commandName);
        }
        return clazz;
    }

    /**
     * Get default implementation class for a command.
     * @param commandName
     * @return
     */
    @SuppressWarnings("unchecked")
    protected Class<AbstractCommand> getCommandClassDefault(String commandName) {
        String className = AbstractConnectorServlet.class.getPackage().getName() + ".commands."
                + StringUtils.capitalize(commandName) + "Command";
        Class<AbstractCommand> clazz = null;
        try {
            clazz = (Class<AbstractCommand>) Class.forName(className);
        } catch (ClassNotFoundException e) {
            // not found
        }
        return clazz;
    }

    /**
     * Get override implementation class for a command.
     * @param commandName
     * @return
     */
    @SuppressWarnings("unchecked")
    protected Class<AbstractCommand> getCommandClassOverride(String commandName) {
        String className = AbstractConnectorServlet.class.getPackage().getName() + ".commands."
                + StringUtils.capitalize(commandName) + "CommandOverride";
        Class<AbstractCommand> clazz = null;
        try {
            clazz = (Class<AbstractCommand>) Class.forName(className);
        } catch (ClassNotFoundException e) {
            // not found
        }
        return clazz;
    }

    /**
     * Append data to JSON response.
     * @param param
     * @param value
     */
    protected void putResponse(String param, Object value) {
        try {
            json.put(param, value);
        } catch (JSONException e) {
            logger.error("json write error", e);
        }
    }
}