de.iteratec.turm.servlets.TurmServlet.java Source code

Java tutorial

Introduction

Here is the source code for de.iteratec.turm.servlets.TurmServlet.java

Source

/*
 * iTURM is a User and Roles Management web application developed by iteratec, GmbH
 * Copyright (C) 2008 iteratec, GmbH
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY ITERATEC, ITERATEC DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact iteratec GmbH headquarters at Inselkammerstrae 4
 * 82008 Mnchen - Unterhaching, Germany, or at email address info@iteratec.de.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "iteraplan" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by iteraplan".
 */
package de.iteratec.turm.servlets;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.RequestDispatcher;
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 org.apache.commons.beanutils.BeanUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import de.iteratec.turm.common.Logger;
import de.iteratec.turm.dao.RoleDao;
import de.iteratec.turm.dao.UserDao;
import de.iteratec.turm.exceptions.DaoException;
import de.iteratec.turm.exceptions.TurmException;
import de.iteratec.turm.messages.TurmMessage;
import de.iteratec.turm.model.IdEntity;

/**
 * Base class for all Turm servlets.
 * 
 * It provides the following functionality:
 * <ul>
 *  <li>The locale of the user is determined and stored for future access.
 *  <li>Errors are logged, stored in the request and converted to {@link TurmException}s if necessary.
 *  <li>After a get or a post request, the request is always forwarded to the JSP defined in {@link #getJsp()}
 *  <li>It provides several common methods for subclasses.
 * </ul>
 */
public abstract class TurmServlet extends HttpServlet {

    private static final long serialVersionUID = -6366990616826366380L;

    private static final Logger LOGGER = Logger.getLogger(TurmServlet.class);

    /** TurmExceptions that occurred will be saved as an request attribute under this key. */
    private static final String ERROR_PARAM_KEY = "turmExceptions";

    /** TurmMessages that are to be displayed will be saved as an request attribute under this key. */
    private static final String MESSAGE_PARAM_KEY = "turmMessages";

    /** The current Locale will be saved in the session under this key. */
    private static final String CURRENT_LOCALE_KEY = "turmLocale";

    /** The URI of the servlet will be stored as a request attribute under this key.
     *  This is used by common JSP tiles that post data to the currently active servlet. */
    private static final String SERVLET_URI = "servletURI";

    /** The current locale. */
    private Locale currentLocale;

    @Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        LOGGER.debug("============================== GET REQUEST ==============================");
        logRequestParameters(request);
        setAndStoreCurrentLocale(request);
        storeServletPath(request);
        try {
            doTurmGet(request);
        } catch (TurmException e) {
            saveErrors(e, request);
        } catch (Exception e) {
            saveErrors(new TurmException("error.internalError", e), request);
        }
        RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(getJsp());
        dispatcher.forward(request, response);
    }

    @Override
    protected final void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        LOGGER.debug("============================== POST REQUEST ==============================");
        logRequestParameters(request);
        setAndStoreCurrentLocale(request);
        storeServletPath(request);
        try {
            doTurmPost(request);
        } catch (TurmException e) {
            saveErrors(e, request);
        } catch (Exception e) {
            saveErrors(new TurmException("error.internalError", e), request);
        }
        RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(getJsp());
        dispatcher.forward(request, response);
    }

    /**
     * Process the current GET request and execute the necessary actions.
     * 
     * @param request The current request.
     * @throws TurmException If there occurred an error while processing the request.
     */
    protected abstract void doTurmGet(HttpServletRequest request) throws TurmException;

    /**
     * Process the current POST request and execute the necessary actions
     * 
     * @param request The current request.
     * @throws TurmException If there occurred an error while processing the request.
     */
    protected abstract void doTurmPost(HttpServletRequest request) throws TurmException;

    /**
     * @return The JSP the Servlet will forward to when it's done, no matter if an error
     *         occured or not.
     */
    protected abstract String getJsp();

    /**
     * Store the URI of this servlet in a request attribute, so that JSPs have
     * access to it.
     * 
     * @param request The current Serlvet Request
     */
    private void storeServletPath(HttpServletRequest request) {
        request.setAttribute(SERVLET_URI, request.getRequestURI());
    }

    /**
     * Log the parameters contained in the given request for
     * debugging purposes.
     * 
     * @param request The current Serlvet Request
     */
    @SuppressWarnings("unchecked")
    private void logRequestParameters(HttpServletRequest request) {
        if (!LOGGER.isDebugEnabled()) {
            return;
        }
        LOGGER.debug("-------------- Parameters in request --------------");
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (Iterator<Map.Entry<String, String[]>> it = parameterMap.entrySet().iterator(); it.hasNext();) {
            Map.Entry<String, String[]> entry = it.next();
            LOGGER.debug(entry.getKey() + ": ");
            String[] value = entry.getValue();
            String parametersValues = "\t";
            for (int i = 0; i < value.length; i++) {
                if (i > 0) {
                    parametersValues += ", ";
                }
                parametersValues += value[i];
            }
            LOGGER.debug(parametersValues);
        }
        LOGGER.debug("---------------------------------------------------");
    }

    /**
     * Store a TurmException in a request attribute, so that it can be rendered
     * by a JSP.
     * 
     * @param e The TurmException to store.
     * @param request The current Serlvet Request
     */
    @SuppressWarnings("unchecked")
    protected final void saveErrors(TurmException e, HttpServletRequest request) {
        LOGGER.info("An error occurred", e);
        List<TurmException> errors = (List<TurmException>) request.getAttribute(ERROR_PARAM_KEY);
        if (errors == null) {
            errors = new ArrayList<TurmException>();
        }
        errors.add(e);
        request.setAttribute(ERROR_PARAM_KEY, errors);
    }

    /**
     * Store a TurmMessage in a request attribute, so that it can be rendered
     * by a JSP.
     * 
     * @param message The TurmMessage to store.
     * @param request The current Serlvet Request
     */
    @SuppressWarnings("unchecked")
    protected final void saveMessages(TurmMessage message, HttpServletRequest request) {
        LOGGER.info("Message to be displayed: " + message.getMessageKey());
        List<TurmMessage> messages = (List<TurmMessage>) request.getAttribute(MESSAGE_PARAM_KEY);
        if (messages == null) {
            messages = new ArrayList<TurmMessage>();
        }
        messages.add(message);
        request.setAttribute(MESSAGE_PARAM_KEY, messages);
    }

    /**
     * Parameters that are contained in the current request are used to fill
     * a given Java Bean. This is similar to the way Struts fills its ActionForms.
     * 
     * @param request The current Serlvet Request
     * @param bean A JavaBean that is to be populated.
     * @throws TurmException If the JavaBean could not be populated.
     */
    @SuppressWarnings("unchecked")
    protected final void populate(HttpServletRequest request, Object bean) throws TurmException {
        HashMap<String, String[]> map = new HashMap<String, String[]>();
        Enumeration<String> names = request.getParameterNames();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            map.put(name, request.getParameterValues(name));
        }
        try {
            BeanUtils.populate(bean, map);
        } catch (IllegalAccessException e) {
            throw new TurmException("error.internal", e);
        } catch (InvocationTargetException e) {
            throw new TurmException("error.internal", e);
        }
    }

    /**
     * Determines the current Locale, stores it in the session and returns it.
     * 
     * It first checks, if a request parameter contains the current locale. This
     * means the user has selected a different locale. Otherwise, it tries to
     * retrieve the locale from the session. If that doesn't exist, the current
     * locale is taken from the request itself.
     * 
     * @param request The current Serlvet Request
     * @return The current Locale as set by the user, or as stored in the session.
     */
    private Locale setAndStoreCurrentLocale(HttpServletRequest request) {
        HttpSession session = request.getSession();
        Locale currentLocaleToSet;
        if (request.getParameter(CURRENT_LOCALE_KEY) != null) {
            String parameterLocale = request.getParameter(CURRENT_LOCALE_KEY);
            if (parameterLocale.equals("de")) {
                currentLocaleToSet = Locale.GERMAN;
            } else {
                currentLocaleToSet = Locale.ENGLISH;
            }
            LOGGER.debug("Locale created from HTTP parameter: " + currentLocaleToSet);
        } else if (session.getAttribute(CURRENT_LOCALE_KEY) != null) {
            currentLocaleToSet = (Locale) session.getAttribute(CURRENT_LOCALE_KEY);
            LOGGER.debug("Locale loaded from session: " + currentLocaleToSet);
        } else {
            currentLocaleToSet = request.getLocale();
            if (currentLocaleToSet.getLanguage().toUpperCase().matches(".*DE.*")) {
                currentLocaleToSet = Locale.GERMAN;
            } else {
                currentLocaleToSet = Locale.ENGLISH;
            }
            LOGGER.debug(
                    "Locale loaded from HTTP request header. Language is: " + currentLocaleToSet.getLanguage());
        }
        this.currentLocale = currentLocaleToSet;
        session.setAttribute(CURRENT_LOCALE_KEY, currentLocale);
        return currentLocale;
    }

    /**
     * @return The current Locale
     */
    protected final Locale getCurrentLocale() {
        return this.currentLocale;
    }

    /**
     * Generic method to remove a list of IdEntity from another list of IdEntity.
     * 
     * @param <T> The type must extend IdEntity
     * @param entitiesToSortOut The IdEntity list to remove.
     * @param allEntities The IdEntity list from which elements are to be removed.
     * @return The allEntities list minus the entitiesToSortOut list.
     */
    protected final <T extends IdEntity> List<T> sortOutIdEntities(List<T> entitiesToSortOut, List<T> allEntities) {
        Set<Number> ids = new HashSet<Number>();
        for (Iterator<T> it = entitiesToSortOut.iterator(); it.hasNext();) {
            T entity = it.next();
            ids.add(entity.getId());
        }
        List<T> result = new ArrayList<T>(allEntities);
        for (Iterator<T> it = result.iterator(); it.hasNext();) {
            T entity = it.next();
            if (ids.contains(entity.getId())) {
                it.remove();
            }
        }
        return result;
    }

    /**
     * @return
     * @throws DaoException
     */
    protected UserDao getUserDao() throws DaoException {
        WebApplicationContext springCtx = WebApplicationContextUtils
                .getWebApplicationContext(this.getServletContext());
        return springCtx.getBean(UserDao.class);
    }

    /**
     * @return
     * @throws DaoException
     */
    protected RoleDao getRoleDao() throws DaoException {
        WebApplicationContext springCtx = WebApplicationContextUtils
                .getWebApplicationContext(this.getServletContext());
        return springCtx.getBean(RoleDao.class);
    }

}