net.sf.ginp.GinpServlet.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.ginp.GinpServlet.java

Source

/*
 *  ginp - Java Web Application for Viewing Photo Collections
 *  Copyright (C) 2004  Douglas John Culnane <doug@culnane.net>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA  02110-1301  USA
 */
package net.sf.ginp;

import net.sf.ginp.config.Configuration;
import net.sf.ginp.config.ModelUtil;

// File Upload.
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;

import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.PrintWriter;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Vector;

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

/**
 *  The Controller servlet of the Model View Controller Architecture.
 *
 *@author     Doug Culnane
 *@author          Justin Sher
 *@version    $Revision$
 */
public class GinpServlet extends HttpServlet {
    /**
     *
     */
    private static final long serialVersionUID = -3290204438867284907L;

    /**
     *  apache Commons Logger specific to this class.
     */
    private static Logger log = Logger.getLogger(GinpServlet.class);

    public final void init() {
        Configuration
                .setConfigfilelocation(getServletContext().getRealPath(Configuration.PATH_TO_CONFIG_FROM_WEBROOT));
    }

    /**
    *  Called by HTTP GET, feeds doHttpMethod.
    *
    *@param  req                   HTTP GET Request
    *@param  res                   HTTP Response
    *@exception  IOException       Description of the Exception
    */
    public final void doGet(final HttpServletRequest req, final HttpServletResponse res) throws IOException {
        doHttpMethod(req, res);
    }

    /**
     *  Called by HTTP POST, feeds doHttpMethod.
     *
     *@param  req                   HTTP POST Request
     *@param  res                   HTTP Response
     *@exception  IOException       Description of the Exception
     */
    public final void doPost(final HttpServletRequest req, final HttpServletResponse res) throws IOException {
        doHttpMethod(req, res);
    }

    /**
     *  Central Processor of HTTP Methods. This method gets the model for the
     *  users session, extracts the Command Parameters and preforms the command
     *  specified in the request. It then redirects or if cookies are used
     *  forwards the response to the JSP govened by the new state. If a
     *  significant error occurs it should be throwned up to here so that a
     *  debug page can be displayed. If a user sees a debug page then that is
     *  bad so lets try to find out about it and so we can fix it.
     *
     *@param  req                   HTTP Request
     *@param  res                   HTTP Response
     *@exception  IOException       Description of the Exception
     */
    public final void doHttpMethod(final HttpServletRequest req, final HttpServletResponse res) throws IOException {
        // Set the Character Encoding. Do this first before access ing the req
        // and res objects, otherwise they take the system default.
        try {
            req.setCharacterEncoding(Configuration.getCharacterEncoding());

            //res.setCharacterEncoding(Configuration.getCharacterEncoding());
            res.setContentType("text/html; charset=\"" + Configuration.getCharacterEncoding() + "\"");
            setNoCache(res);

            // Debug
            log.debug("req.getContentType(): " + req.getContentType());
            log.debug("Request Charactor Encoding:" + req.getCharacterEncoding());
        } catch (java.io.UnsupportedEncodingException e) {
            log.error("Error setting Character Encoding. Check Configuration", e);
        }

        try {
            //Retrieve the model for this web app
            GinpModel model = ModelUtil.getModel(req);

            //This controller modifies the model via commands
            executeCommand(req, model);

            // The updated model is now available in the request,
            // go to the view page
            String url = model.getCurrentPage();

            // debug to log
            if (log.isDebugEnabled()) {
                log.debug("doHttpMethod url=" + url + " " + model.getDebugInfo());
            }

            // Forward to New URL
            forwardToPage(req, res, url);

            // debug to log
            if (log.isDebugEnabled()) {
                log.debug("DONE");
            }
        } catch (Exception ex) {
            log.error("doHttpMethod", ex);
            handleError(req, res, ex);
        }
    }

    /**
     * Deliver the view that the controller has selected.  Do this in
     * a way that the page is not cached.  Also works around a bug in
     * Session URL Encdoing in Tomcat
     * @param req  The Servlet Request
     * @param res  The Servlet response
     * @param url The URL To send to
     * @throws IOException if there is an error retrieving or
     * sending the page
     * @throws ServletException if there is some other error
     */
    private void forwardToPage(final HttpServletRequest req, final HttpServletResponse res, String url)
            throws IOException, ServletException {
        Random rnd = new Random();

        // Add no cache random number
        if (url.indexOf("?") == -1) {
            url = res.encodeRedirectURL(url + "?nocache=" + rnd.nextInt(999999999));
        } else {
            // Pass the parameters throught the urlEncodeParameters method
            url = res.encodeRedirectURL(url + "&nocache=" + rnd.nextInt(999999999));
        }

        // Add the Path
        if (!url.startsWith("/")) {
            String serPath = req.getServletPath();
            url = serPath.substring(0, serPath.lastIndexOf("/")) + "/" + url;
        }

        // if ;jsessionid= then cookies not used so it is safer to redirect
        // than forward, due to a bug (or spec requirement) in Tomcat 4
        if (url.indexOf(";jsessionid=") != -1) {
            // debug to log
            if (log.isDebugEnabled()) {
                log.debug("redirect to new page url=" + url);
            }

            // redirect to new page
            res.sendRedirect(url);
        } else {
            // debug to log
            if (log.isDebugEnabled()) {
                log.debug("forward to new page url=" + url);
            }

            getServletConfig().getServletContext().getRequestDispatcher(url).forward(req, res);
        }
    }

    /**
     * Dump an error message to the web browser if there was an
     * unexpected error while trying to use the ginp servlet.
     * @param req the servlet request
     * @param res the servlet response
     * @param ex the exception thrown
     * @throws IOException If there was an error sending the error message
     */
    private void handleError(final HttpServletRequest req, final HttpServletResponse res, final Exception ex)
            throws IOException {
        log.error("Show error page with debug info", ex);

        // Show error page with debug info.
        res.setContentType("text/html");

        PrintWriter out = res.getWriter();
        out.print("<html>\n" + "<body>\n" + "<head>\n" + "<title>ginp - ERROR!</title>\n" + "</head>\n" + "<body>\n"
                + "<h1>ginp - ERROR!</h1>\n" + "<p>If you are seeing this page and do not understand "
                + "it then there is someone who is sorry and will try "
                + "to fix the fault of the software. To inform them of " + "the fault please <a href=\"mailto:"
                + "ginp-users@lists.sourceforge.net" + "?subject=Error Report&body=");
        ex.printStackTrace(res.getWriter());
        out.print("\">click Here.</a></p>" + "<h2>Debug info for Developers</h2>\n" + "<pre>\n");
        ex.printStackTrace(res.getWriter());
        out.print("</pre>\n" + "<h2>Model State</h2>\n" + "<pre>\n");

        try {
            GinpModel model = ModelUtil.getModel(req);
            out.print(model.getDebugDump());
        } catch (Exception e) {
            log.error("Error showing error page", e);
        }

        out.print("</pre>\n" + "</body>\n" + "</html>\n");
    }

    /**
     * Run the controller. The model will be able to tell you what view
     * to use with model.getCurrentPage() after this is run and the request
     * and model will have the information needed for the view.
     * @param req the servlet request
     * @param model the model
     */
    private void executeCommand(final HttpServletRequest req, final GinpModel model) {
        //If a Command was issued run it
        String command = req.getParameter("cmd");

        if (command != null) {
            if (command.length() > 0) {
                Vector params = extractParameters(req);

                // perform command
                model.doCommand(command, params);
            }
        }
    }

    /**
     * Sets the headers on the servlet request such that
     * the page is not cached.
     * @param res the servlet response
     */
    private void setNoCache(final HttpServletResponse res) {
        // DO NOT cache the output form this servlet.
        res.setHeader("Expires", "-1");
        res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        res.addHeader("Cache-Control", "post-check=0, pre-check=0");
        res.setHeader("Pragma", "no-cache");
    }

    /**
    *  Extract Command Parameter NAmes and Values from the HTTP Request.
    *
    *@param  req  HTTP Request.
    *@return      A vector of Command Parameters.
    */
    final Vector extractParameters(final HttpServletRequest req) {
        Vector params = new Vector();
        Enumeration names = req.getParameterNames();

        while (names.hasMoreElements()) {
            String name = (String) names.nextElement();
            params.add(new CommandParameter(name, req.getParameter(name)));
            log.debug("new CommandParameter(" + name + ", " + req.getParameter(name) + ")");
        }

        ServletRequestContext reqContext = new ServletRequestContext(req);

        if (FileUpload.isMultipartContent(reqContext)) {
            try {
                // Create a new file upload handler
                ServletFileUpload upload = new ServletFileUpload();

                // Set upload parameters
                //upload.setSizeThreshold(yourMaxMemorySize);
                //upload.setSizeMax(yourMaxRequestSize);
                //upload.setRepositoryPath(yourTempDirectory);
                // Parse the request
                List items = upload.parseRequest(req);
                Iterator iter = items.iterator();

                while (iter.hasNext()) {
                    FileItem item = (FileItem) iter.next();

                    if (item.isFormField()) {
                        params.add(new CommandParameter(item.getFieldName(), item.getString()));
                    } else {
                        CommandParameter fileParam = new CommandParameter(item.getFieldName(), item.getName());

                        fileParam.setObject(item.getInputStream());

                        params.add(fileParam);
                    }
                }
            } catch (Exception ex) {
                log.error("extract parameters error getting input stream" + " from file upload", ex);
            }
        }

        return params;
    }
}