MVCApplication.java

/*
 * Copyright (c) 2002-2022, City of Paris
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice
 *     and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright notice
 *     and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *
 *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * License 1.0
 */
package fr.paris.lutece.portal.util.mvc.xpage;

import fr.paris.lutece.portal.service.security.AccessLogService;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;

import org.apache.logging.log4j.Logger;
import org.springframework.util.ReflectionUtils;

import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.message.SiteMessageException;
import fr.paris.lutece.portal.service.plugin.Plugin;
import fr.paris.lutece.portal.service.security.AccessLoggerConstants;
import fr.paris.lutece.portal.service.security.LuteceUser;
import fr.paris.lutece.portal.service.security.SecurityService;
import fr.paris.lutece.portal.service.security.UserNotSignedException;
import fr.paris.lutece.portal.service.template.AppTemplateService;
import fr.paris.lutece.portal.service.util.AppException;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.portal.util.mvc.utils.MVCMessage;
import fr.paris.lutece.portal.util.mvc.utils.MVCMessageBox;
import fr.paris.lutece.portal.util.mvc.utils.MVCUtils;
import fr.paris.lutece.portal.util.mvc.xpage.annotations.Controller;
import fr.paris.lutece.portal.web.LocalVariables;
import fr.paris.lutece.portal.web.l10n.LocaleService;
import fr.paris.lutece.portal.web.xpages.XPage;
import fr.paris.lutece.portal.web.xpages.XPageApplication;
import fr.paris.lutece.util.ErrorMessage;
import fr.paris.lutece.util.bean.BeanUtil;
import fr.paris.lutece.util.beanvalidation.BeanValidationUtil;
import fr.paris.lutece.util.html.HtmlTemplate;
import fr.paris.lutece.util.url.UrlItem;

/**
 * MVC XPage Application
 */
public abstract class MVCApplication implements XPageApplication
{
    private static final long serialVersionUID = 6093635383465830355L;

    // markers
    private static final String MARK_ERRORS = "errors";
    private static final String MARK_INFOS = "infos";
    private static final String MARK_WARNINGS = "warnings";
    private static final String MARK_MESSAGE_BOX = "messageBox";

    // constants
    private static final String URL_PORTAL = "Portal.jsp";
    private static final String PATH_PORTAL = "jsp/site/";
    private static final String VIEW_MESSAGEBOX = "messageBox";
    private static final String CONTENT_TYPE_JSON = "application/json";
    private static final String CONTENT_TYPE_XML = "application/xml";

    // instance vars
    private static Logger _logger = MVCUtils.getLogger( );
    private List<ErrorMessage> _listErrors = new ArrayList<>( );
    private List<ErrorMessage> _listInfos = new ArrayList<>( );
    private List<ErrorMessage> _listWarnings = new ArrayList<>( );
    private MVCMessageBox _messageBox;
    private Controller _controller = getClass( ).getAnnotation( Controller.class );

    /**
     * Returns the content of the page
     *
     * @param request
     *            The http request
     * @param nMode
     *            The current mode
     * @param plugin
     *            The plugin object
     * @return The XPage
     * @throws fr.paris.lutece.portal.service.message.SiteMessageException
     *             Message displayed if an exception occurs
     * @throws UserNotSignedException
     *             if an authentication is required by a view
     */
    @Override
    public XPage getPage( HttpServletRequest request, int nMode, Plugin plugin ) throws SiteMessageException, UserNotSignedException
    {
        return processController( request );
    }

    // //////////////////////////////////////////////////////////////////////////
    // Controller

    /**
     * XPage controller
     * 
     * @param request
     *            The HTTP request
     * @return The XPage
     * @throws UserNotSignedException
     *             if an authentication is required by a view
     * @throws SiteMessageException
     *             if a message is thrown by an action
     */
    private XPage processController( HttpServletRequest request ) throws UserNotSignedException, SiteMessageException
    {
        Method [ ] methods = ReflectionUtils.getAllDeclaredMethods( getClass( ) );

        try
        {
            if ( isMessageBox( request ) )
            {
                return messageBox( request );
            }

            LuteceUser registredUser = getRegistredUser( request );

            // Process views
            Method m = MVCUtils.findViewAnnotedMethod( request, methods );

            if ( m != null )
            {
                AccessLogService.getInstance( ).trace( AccessLoggerConstants.EVENT_TYPE_READ, m.getName( ), registredUser,
                        request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_FO );
                return (XPage) m.invoke( this, request );
            }

            // Process actions
            m = MVCUtils.findActionAnnotedMethod( request, methods );

            if ( m != null )
            {
                AccessLogService.getInstance( ).debug( AccessLoggerConstants.EVENT_TYPE_ACTION, m.getName( ), registredUser,
                        request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_FO );
                return (XPage) m.invoke( this, request );
            }

            // No view or action found so display the default view
            m = MVCUtils.findDefaultViewMethod( methods );

            AccessLogService.getInstance( ).trace( AccessLoggerConstants.EVENT_TYPE_ACTION, m.getName( ), registredUser,
                    request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_FO );
            return (XPage) m.invoke( this, request );
        }
        catch( InvocationTargetException e )
        {
            if ( e.getTargetException( ) instanceof UserNotSignedException )
            {
                throw (UserNotSignedException) e.getTargetException( );
            }

            if ( e.getTargetException( ) instanceof SiteMessageException )
            {
                throw (SiteMessageException) e.getTargetException( );
            }

            if ( e.getTargetException( ) instanceof RuntimeException )
            {
                throw new AppException( "MVC Error dispaching view and action ", (RuntimeException) e.getTargetException( ) );
            }

            throw new AppException( "MVC Error dispaching view and action ", e );
        }
        catch( IllegalAccessException e )
        {
            throw new AppException( "MVC Error dispaching view and action ", e );
        }
    }

    /**
     * Returns the XPage name
     * 
     * @return The XPage name
     */
    protected String getXPageName( )
    {
        return _controller.xpageName( );
    }

    /**
     * Returns the default page title
     * 
     * @param locale
     *            The locale
     * @return The default page title
     */
    protected String getDefaultPageTitle( Locale locale )
    {
        if ( !_controller.pageTitleProperty( ).equals( "" ) )
        {
            return AppPropertiesService.getProperty( _controller.pageTitleProperty( ) );
        }
        else
            if ( !_controller.pageTitleI18nKey( ).equals( "" ) )
            {
                return I18nService.getLocalizedString( _controller.pageTitleI18nKey( ), locale );
            }

        return _controller.xpageName( );
    }

    /**
     * Returns the default page path
     * 
     * @param locale
     *            The locale
     * @return The default pagepath
     */
    protected String getDefaultPagePath( Locale locale )
    {
        if ( !_controller.pagePathProperty( ).equals( "" ) )
        {
            return AppPropertiesService.getProperty( _controller.pagePathProperty( ) );
        }
        else
            if ( !_controller.pagePathI18nKey( ).equals( "" ) )
            {
                return I18nService.getLocalizedString( _controller.pagePathI18nKey( ), locale );
            }

        return _controller.xpageName( );
    }

    // //////////////////////////////////////////////////////////////////////////
    // XPage utils

    /**
     * Returns a new XPage object with default values
     * 
     * @return An XPage Object
     */
    protected XPage getXPage( )
    {
        XPage page = new XPage( );

        page.setTitle( getDefaultPageTitle( LocaleService.getDefault( ) ) );
        page.setPathLabel( getDefaultPagePath( LocaleService.getDefault( ) ) );

        return page;
    }

    /**
     * Returns a new XPage object with default values and the content filled by a template
     * 
     * @param strTemplate
     *            The template
     * @return An XPage Object
     */
    protected XPage getXPage( String strTemplate )
    {
        XPage page = getXPage( );

        HtmlTemplate t = AppTemplateService.getTemplate( strTemplate );
        page.setContent( t.getHtml( ) );

        return page;
    }

    /**
     * Returns a new XPage object with default values and the content filled by a template using a default model and for a given locale
     * 
     * @param strTemplate
     *            The template
     * @param locale
     *            The locale
     * @return An XPage Object
     */
    protected XPage getXPage( String strTemplate, Locale locale )
    {
        return getXPage( strTemplate, locale, getModel( ) );
    }

    /**
     * Returns a new XPage object with default values and the content filled by a template using a given model and for a given locale
     * 
     * @param strTemplate
     *            The template
     * @param locale
     *            The locale
     * @param model
     *            The model
     *
     * @return An XPage Object
     */
    protected XPage getXPage( String strTemplate, Locale locale, Map<String, Object> model )
    {
        XPage page = getXPage( );

        HtmlTemplate t = AppTemplateService.getTemplate( strTemplate, locale, model );
        page.setContent( t.getHtml( ) );
        page.setTitle( getDefaultPageTitle( locale ) );
        page.setPathLabel( getDefaultPagePath( locale ) );

        return page;
    }

    /**
     * Get a model Object filled with default values
     * 
     * @return The model
     */
    protected Map<String, Object> getModel( )
    {
        Map<String, Object> model = new HashMap<>( );
        fillCommons( model );

        return model;
    }

    // //////////////////////////////////////////////////////////////////////////
    // Bean processing

    /**
     * Populate a bean using parameters in http request
     * 
     * @param bean
     *            bean to populate
     * @param request
     *            http request
     */
    protected void populate( Object bean, HttpServletRequest request )
    {
        BeanUtil.populate( bean, request, null );
    }

    /**
     * Populate a bean using parameters in http request, with locale date format controls
     * 
     * @param bean
     *            bean to populate
     * @param request
     *            http request
     * @param locale
     *            the locale
     */
    protected void populate( Object bean, HttpServletRequest request, Locale locale )
    {
        BeanUtil.populate( bean, request, locale );
    }

    /**
     * Validate a bean. If the validation failed, error messages of this MVCApplication are updated.<br>
     * This method should be used only if error messages of constraints of the bean are NOT i18n Keys. If they are I18n keys, the method
     * {@link #validateBean(Object, Locale)} should be used instead.
     * 
     * @param <T>
     *            The bean class
     * @param bean
     *            The bean
     * @return true if validated otherwise false
     */
    protected <T> boolean validateBean( T bean )
    {
        Set<ConstraintViolation<T>> errors = BeanValidationUtil.validate( bean );

        if ( errors.isEmpty( ) )
        {
            return true;
        }

        for ( ConstraintViolation<T> constraint : errors )
        {
            MVCMessage error = new MVCMessage( );
            error.setMessage( constraint.getMessage( ) );
            _listErrors.add( error );
        }

        return false;
    }

    /**
     * Validate a bean. If the validation failed, error messages of this MVCApplication are updated.<br>
     * This method should be used only if error messages of constraints of the bean are i18n Keys. If they are not I18n keys, the method
     * {@link #validateBean(Object)} should be used instead.
     * 
     * @param <T>
     *            The bean class
     * @param bean
     *            The bean
     * @param locale
     *            The locale
     * @return true if validated otherwise false
     */
    protected <T> boolean validateBean( T bean, Locale locale )
    {
        Set<ConstraintViolation<T>> errors = BeanValidationUtil.validate( bean );

        if ( errors.isEmpty( ) )
        {
            return true;
        }

        for ( ConstraintViolation<T> constraint : errors )
        {
            MVCMessage error = new MVCMessage( );
            error.setMessage( I18nService.getLocalizedString( constraint.getMessage( ), locale ) );
            _listErrors.add( error );
        }

        return false;
    }

    /**
     * Add an error message. The error message must NOT be an I18n key.
     * 
     * @param strMessage
     *            The message
     */
    protected void addError( String strMessage )
    {
        _listErrors.add( new MVCMessage( strMessage ) );
    }
    
    /**
     * Add an error message. The error message must NOT be an I18n key.
     * 
     * @param strMessage
     *            The message
     * @param  strFieldName the field name           
     */
    protected void addError( String strMessage, String strFieldName )
    {
        _listErrors.add( new MVCMessage( strMessage,strFieldName ) );
    }

    /**
     * Add an error message. The error message must be an I18n key.
     * 
     * @param strMessageKey
     *            The message
     * @param locale
     *            The locale to display the message in
     */
    protected void addError( String strMessageKey, Locale locale )
    {
        _listErrors.add( new MVCMessage( I18nService.getLocalizedString( strMessageKey, locale ) ) );
    }

    
    /**
     * Add an warning message. The warning message must NOT be an I18n key.
     * 
     * @param strMessage
     *            The message
     */
    protected void addWarning( String strMessage )
    {
        _listWarnings.add( new MVCMessage( strMessage ) );
    }
    
    /**
     * Add an warning message. The warning message must NOT be an I18n key.
     * 
     * @param strMessage
     *            The message
     *            
     * @param  strFieldName the field name            
     *            
     */
    protected void addWarning( String strMessage, String strFieldName  )
    {
        _listWarnings.add( new MVCMessage( strMessage,strFieldName ) );
    }
    


    /**
     * Add an warning message. The warning message must be an I18n key.
     * 
     * @param strMessageKey
     *            The message
     * @param locale
     *            The locale to display the message in
     */
    protected void addWarning( String strMessageKey, Locale locale )
    {
        _listWarnings.add( new MVCMessage( I18nService.getLocalizedString( strMessageKey, locale ) ) );
    }

    /**
     * Add an info message. The info message must NOT be an I18n key.
     * 
     * @param strMessage
     *            The message
     */
    protected void addInfo( String strMessage )
    {
        _listInfos.add( new MVCMessage( strMessage ) );
    }
    
    /**
     * Add an info message. The info message must NOT be an I18n key.
     * 
     * @param strMessage
     *            The message
     * @param  strFieldName the field name             
     */
    protected void addInfo( String strMessage, String strFieldName )
    {
        _listInfos.add( new MVCMessage( strMessage,strFieldName )  );
    }

    /**
     * Add an info message. The info message must be an I18n key.
     * 
     * @param strMessageKey
     *            The message key
     * @param locale
     *            The locale to display the message in
     */
    protected void addInfo( String strMessageKey, Locale locale )
    {
        _listInfos.add( new MVCMessage( I18nService.getLocalizedString( strMessageKey, locale ) ) );
    }

    /**
     * Fill the model with commons objects used in templates
     * 
     * @param model
     *            The model
     */
    protected void fillCommons( Map<String, Object> model )
    {
        List<ErrorMessage> listErrors = new ArrayList<>( _listErrors );
        List<ErrorMessage> listInfos = new ArrayList<>( _listInfos );
        List<ErrorMessage> listWarnings = new ArrayList<>( _listWarnings );
        model.put( MARK_ERRORS, listErrors );
        model.put( MARK_INFOS, listInfos );
        model.put( MARK_WARNINGS, listWarnings );
        _listErrors.clear( );
        _listInfos.clear( );
        _listWarnings.clear( );
    }

    // //////////////////////////////////////////////////////////////////////////
    // Redirect utils

    /**
     * Redirect to requested page
     *
     * @param request
     *            the http request
     * @param strTarget
     *            the targeted page
     * @return the page requested
     */
    protected XPage redirect( HttpServletRequest request, String strTarget )
    {
        HttpServletResponse response = LocalVariables.getResponse( );

        try
        {
            _logger.debug( "Redirect :{}", strTarget );
            response.sendRedirect( strTarget );
        }
        catch( IOException e )
        {
            _logger.error( "Unable to redirect : {} : {}", strTarget, e.getMessage( ), e );
        }
        XPage xpage=new XPage();
        xpage.setSendRedirect(true);
        return xpage;
    }

    /**
     * Redirect to an url defined by given parameters
     * 
     * @param request
     *            The HTTP request
     * @param strView
     *            The View name
     * @param strParameter
     *            The additional parameter
     * @param nValue
     *            The additional parameter's value
     * @return The XPage redirected
     */
    protected XPage redirect( HttpServletRequest request, String strView, String strParameter, int nValue )
    {
        UrlItem url = new UrlItem( getViewUrl( strView ) );
        url.addParameter( strParameter, nValue );

        return redirect( request, url.getUrl( ) );
    }

    /**
     * Redirect to an url defined by given parameters
     * 
     * @param request
     *            The HTTP request
     * @param strView
     *            The View name
     * @param strParameter1
     *            The first additional parameter
     * @param nValue1
     *            The first additional parameter's value
     * @param strParameter2
     *            The second additionnal parameter
     * @param nValue2
     *            The second additionnal parameter's value
     * @return The XPage redirected
     */
    protected XPage redirect( HttpServletRequest request, String strView, String strParameter1, int nValue1, String strParameter2, int nValue2 )
    {
        UrlItem url = new UrlItem( getViewUrl( strView ) );
        url.addParameter( strParameter1, nValue1 );
        url.addParameter( strParameter2, nValue2 );

        return redirect( request, url.getUrl( ) );
    }

    /**
     * Redirect to an url defined by given parameters
     * 
     * @param request
     *            The HTTP request
     * @param strView
     *            The View name
     * @param additionalParameters
     *            A map containing parameters to add to the URL. Keys of the map are parameters name, and values are parameters values
     * @return The XPage redirected
     */
    protected XPage redirect( HttpServletRequest request, String strView, Map<String, String> additionalParameters )
    {
        UrlItem url = new UrlItem( getViewUrl( strView ) );

        if ( additionalParameters != null )
        {
            for ( Entry<String, String> entry : additionalParameters.entrySet( ) )
            {
                url.addParameter( entry.getKey( ), entry.getValue( ) );
            }
        }

        return redirect( request, url.getUrl( ) );
    }

    /**
     * Redirect to requested view
     *
     * @param request
     *            the http request
     * @param strView
     *            the targeted view
     * @return the page requested
     */
    protected XPage redirectView( HttpServletRequest request, String strView )
    {
        return redirect( request, getViewUrl( strView ) );
    }

    /**
     * Get a View URL
     * 
     * @param strView
     *            The view name
     * @return The URL
     */
    protected String getViewUrl( String strView )
    {
        UrlItem url = new UrlItem( URL_PORTAL );
        url.addParameter( MVCUtils.PARAMETER_PAGE, getXPageName( ) );
        url.addParameter( MVCUtils.PARAMETER_VIEW, strView );

        return url.getUrl( );
    }

    /**
     * Gets the view URL with the JSP path
     * 
     * @param strView
     *            The view
     * @return The URL
     */
    protected String getViewFullUrl( String strView )
    {
        return PATH_PORTAL + getViewUrl( strView );
    }

    /**
     * Get Action URL
     * 
     * @param strAction
     *            The view name
     * @return The URL
     */
    protected String getActionUrl( String strAction )
    {
        UrlItem url = new UrlItem( URL_PORTAL );
        url.addParameter( MVCUtils.PARAMETER_PAGE, getXPageName( ) );
        url.addParameter( MVCUtils.PARAMETER_ACTION, strAction );

        return url.getUrl( );
    }

    /**
     * Get Action URL
     * 
     * @param strAction
     *            The view name
     * @return The URL
     */
    protected String getActionFullUrl( String strAction )
    {
        return PATH_PORTAL + getActionUrl( strAction );
    }

    /**
     * Initiates a file download
     * 
     * @param strData
     *            Data of the file to download
     * @param strFilename
     *            Name of file
     * @param strContentType
     *            content type to set to the response
     * @return The page requested
     */
    protected XPage download( String strData, String strFilename, String strContentType )
    {
        HttpServletResponse response = LocalVariables.getResponse( );
        PrintWriter out = null;
        response.setHeader( "Content-Disposition", "attachment; filename=\"" + strFilename + "\";" );
        MVCUtils.addDownloadHeaderToResponse( response, strFilename, strContentType );

        try
        {
            out = response.getWriter( );
            out.print( strData );
        }
        catch( IOException e )
        {
            AppLogService.error( e.getStackTrace( ), e );
        }
        finally
        {
            if ( out != null )
            {
                out.close( );
            }
        }

        return new XPage( );
    }

    /**
     * Initiates a download of a byte array
     * 
     * @param data
     *            Data to download
     * @param strFilename
     *            Name of the downloaded file
     * @param strContentType
     *            Content type to set to the response
     * @return The page requested
     */
    protected XPage download( byte [ ] data, String strFilename, String strContentType )
    {
        HttpServletResponse response = LocalVariables.getResponse( );
        OutputStream os;
        MVCUtils.addDownloadHeaderToResponse( response, strFilename, strContentType );

        try
        {
            os = response.getOutputStream( );
            os.write( data );
            os.close( );
        }
        catch( IOException e )
        {
            AppLogService.error( e.getStackTrace( ), e );
        }

        return new XPage( );
    }

    /**
     * Return a response as JSON content
     * 
     * @param strJSON
     *            The JSON
     * @return An unused XPage
     */
    protected XPage responseJSON( String strJSON )
    {
        HttpServletResponse response = LocalVariables.getResponse( );
        response.setContentType( CONTENT_TYPE_JSON );

        try
        {
            PrintWriter out = response.getWriter( );
            out.print( strJSON );
            out.flush( );
            out.close( );
        }
        catch( IOException e )
        {
            AppLogService.error( e.getStackTrace( ), e );
        }

        return new XPage( );
    }

    /**
     * Return a response as XML content
     * 
     * @param strXML
     *            The XML
     * @return An unused XPage
     */
    protected XPage responseXML( String strXML )
    {
        HttpServletResponse response = LocalVariables.getResponse( );
        response.setContentType( CONTENT_TYPE_XML );

        try
        {
            PrintWriter out = response.getWriter( );
            out.print( strXML );
            out.flush( );
            out.close( );
        }
        catch( IOException e )
        {
            AppLogService.error( e.getStackTrace( ), e );
        }

        return new XPage( );
    }

    // //////////////////////////////////////////////////////////////////////////
    // MESSAGE BOX MANAGEMENT

    /**
     * Redirect to a Message Box page
     * 
     * @param request
     *            The HTTP request
     * @param messageBox
     *            The MessageBox infos
     * @return A redirect XPage
     */
    protected XPage redirectMessageBox( HttpServletRequest request, MVCMessageBox messageBox )
    {
        _messageBox = messageBox;

        return redirectView( request, VIEW_MESSAGEBOX );
    }

    /**
     * Check if a message box is asked for
     * 
     * @param request
     *            The HTTP request
     * @return If a message box is asked
     */
    private boolean isMessageBox( HttpServletRequest request )
    {
        String strView = request.getParameter( MVCUtils.PARAMETER_VIEW );

        return ( ( strView != null ) && ( strView.equals( VIEW_MESSAGEBOX ) ) );
    }

    /**
     * Default getLocale() implementation. Could be overriden
     * 
     * @param request
     *            The HTTP request
     * @return The Locale
     */
    protected Locale getLocale( HttpServletRequest request )
    {
        return LocaleService.getContextUserLocale( request );
    }

    /**
     * Display the Message BOX
     * 
     * @param request
     *            The HTTP request
     * @return The message box
     */
    private XPage messageBox( HttpServletRequest request )
    {
        _messageBox.localize( getLocale( request ) );

        Map<String, Object> model = getModel( );
        model.put( MARK_MESSAGE_BOX, _messageBox );

        return getXPage( _messageBox.getTemplate( ), getLocale( request ), model );
    }

    /**
     * get the registred User
     * 
     * @param request
     * @return the lutece user if registred, null otherwise
     */
    protected LuteceUser getRegistredUser( HttpServletRequest request )
    {
        // get authenticated user if authentication is enable
        if ( SecurityService.isAuthenticationEnable( ) )
        {
            LuteceUser luteceUser = SecurityService.getInstance( ).getRegisteredUser( request );
            if ( luteceUser != null )
            {
                return luteceUser;
            }
        }

        return null;
    }
}