MVCAdminJspBean.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.admin;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.Logger;
import org.springframework.util.ReflectionUtils;
import fr.paris.lutece.portal.business.user.AdminUser;
import fr.paris.lutece.portal.service.admin.AccessDeniedException;
import fr.paris.lutece.portal.service.admin.AdminAuthenticationService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.security.AccessLoggerConstants;
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.util.mvc.admin.annotations.Controller;
import fr.paris.lutece.portal.util.mvc.utils.MVCMessage;
import fr.paris.lutece.portal.util.mvc.utils.MVCUtils;
import fr.paris.lutece.portal.web.admin.PluginAdminPageJspBean;
import fr.paris.lutece.util.ErrorMessage;
import fr.paris.lutece.util.beanvalidation.ValidationError;
import fr.paris.lutece.util.html.HtmlTemplate;
import fr.paris.lutece.util.url.UrlItem;
/**
* MVC Admin JspBean implementation let use MVC model to develop admin feature.
*/
public abstract class MVCAdminJspBean extends PluginAdminPageJspBean
{
private static final long serialVersionUID = 278165302545398831L;
// markers
private static final String MARK_ERRORS = "errors";
private static final String MARK_INFOS = "infos";
private static final String MARK_WARNINGS = "warnings";
// properties
private static final String PROPERTY_SITE_CODE = "lutece.code";
// 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 Controller _controller = getClass( ).getAnnotation( Controller.class );
private HttpServletResponse _response;
/**
* Process request as a controller
*
* @param request
* The HTTP request
* @param response
* The HTTP response
* @return The page content
* @throws AccessDeniedException
* If the user's has no right
*/
public String processController( HttpServletRequest request, HttpServletResponse response ) throws AccessDeniedException
{
_response = response;
init( request, _controller.right( ) );
Method [ ] methods = ReflectionUtils.getAllDeclaredMethods( getClass( ) );
try
{
// Process views
Method m = MVCUtils.findViewAnnotedMethod( request, methods );
AdminUser adminUser = AdminAuthenticationService.getInstance( ).getRegisteredUser( request );
if ( m != null )
{
AccessLogService.getInstance( ).trace( AccessLoggerConstants.EVENT_TYPE_VIEW, m.getName( ), adminUser,
request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_BO );
return (String) m.invoke( this, request );
}
// Process actions
m = MVCUtils.findActionAnnotedMethod( request, methods );
if ( m != null )
{
AccessLogService.getInstance( ).debug( AccessLoggerConstants.EVENT_TYPE_ACTION, m.getName( ), adminUser,
request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_BO );
return (String) m.invoke( this, request );
}
// No view or action found so display the default view
m = MVCUtils.findDefaultViewMethod( methods );
AccessLogService.getInstance( ).trace( AccessLoggerConstants.EVENT_TYPE_VIEW, m.getName( ), adminUser,
request.getRequestURL( ) + "?" + request.getQueryString( ), AccessLogService.ACCESS_LOG_BO );
return (String) m.invoke( this, request );
}
catch( InvocationTargetException e )
{
if ( e.getTargetException( ) instanceof AccessDeniedException )
{
throw (AccessDeniedException) 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 );
}
}
// //////////////////////////////////////////////////////////////////////////
// Page utils
/**
* Add an error message
*
* @param strMessage
* The message
*/
protected void addError( String strMessage )
{
_listErrors.add( new MVCMessage( strMessage ) );
}
/**
* Add an error message
*
* @param strMessageKey
* The message
* @param locale
* The locale
*/
protected void addError( String strMessageKey, Locale locale )
{
_listErrors.add( new MVCMessage( I18nService.getLocalizedString( strMessageKey, locale ) ) );
}
/**
* Add a warning message
*
* @param strMessage
* The message
*/
protected void addWarning( String strMessage )
{
_listWarnings.add( new MVCMessage( strMessage ) );
}
/**
* Add an warning message
*
* @param strMessageKey
* The message
* @param locale
* The locale
*/
protected void addWarning( String strMessageKey, Locale locale )
{
_listWarnings.add( new MVCMessage( I18nService.getLocalizedString( strMessageKey, locale ) ) );
}
/**
* Add an info message
*
* @param strMessage
* The message
*/
protected void addInfo( String strMessage )
{
_listInfos.add( new MVCMessage( strMessage ) );
}
/**
* Add an info message
*
* @param strMessageKey
* The message key
* @param locale
* The locale
*/
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( );
}
/**
* 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;
}
/**
* Return the page content
*
* @param strTemplate
* The template
* @return The page
*/
protected String getPage( String strTemplate )
{
String strPageTitleProperty = _controller.pageTitleProperty( );
return getPage( strPageTitleProperty, strTemplate, getModel( ) );
}
/**
* Return the page content
*
* @param strPageTitleProperty
* The page title property
* @param strTemplate
* The template
* @return The page
*/
protected String getPage( String strPageTitleProperty, String strTemplate )
{
return getPage( strPageTitleProperty, strTemplate, getModel( ) );
}
/**
* Return the page content
*
* @param strPageTitleProperty
* The page title property
* @param strTemplate
* The template
* @param model
* The model
* @return The page
*/
protected String getPage( String strPageTitleProperty, String strTemplate, Map<String, Object> model )
{
setPageTitleProperty( strPageTitleProperty );
HtmlTemplate template = AppTemplateService.getTemplate( strTemplate, getLocale( ), model );
return getAdminPage( template.getHtml( ) );
}
/**
* Validate a bean
*
* @param <T>
* The bean class
* @param bean
* The bean
* @param strPrefix
* The prefix
* @return true if validated otherwise false
*/
protected <T> boolean validateBean( T bean, String strPrefix )
{
List<ValidationError> errors = validate( bean, strPrefix );
if ( errors.isEmpty( ) )
{
return true;
}
for ( ValidationError errorValidation : errors )
{
MVCMessage error = new MVCMessage( );
error.setMessage( errorValidation.getMessage( ) );
error.setFieldName( errorValidation.getFieldName( ) );
_listErrors.add( error );
}
return false;
}
// //////////////////////////////////////////////////////////////////////////
// Redirect utils
/**
* Return the JSP name used as controller
*
* @return The JSP name
*/
protected String getControllerJsp( )
{
return _controller.controllerJsp( );
}
/**
* Return the path of the JSP used as controller
*
* @return The controller path
*/
protected String getControllerPath( )
{
return _controller.controllerPath( );
}
/**
* Redirect to requested page
*
* @param request
* the http request
* @param strTarget
* the targeted page
* @return null. The page should be redirected
*/
protected String redirect( HttpServletRequest request, String strTarget )
{
try
{
_logger.debug( "Redirect : {}", strTarget );
_response.sendRedirect( strTarget );
}
catch( IOException e )
{
_logger.error( "Unable to redirect : {} : {}", strTarget, e.getMessage( ), e );
}
return null;
}
/**
* 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 redirection result
*/
protected String 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 redirection result
*/
protected String 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 String 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 redirection result
*/
protected String 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( getControllerJsp( ) );
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 getControllerPath( ) + getViewUrl( strView );
}
/**
* Get Action URL
*
* @param strAction
* The view name
* @return The URL
*/
protected String getActionUrl( String strAction )
{
UrlItem url = new UrlItem( getControllerPath( ) + getControllerJsp( ) );
url.addParameter( MVCUtils.PARAMETER_ACTION, strAction );
return url.getUrl( );
}
/**
* 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
*/
protected void download( String strData, String strFilename, String strContentType )
{
HttpServletResponse response = _response;
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( );
}
}
}
/**
* 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
*/
protected void download( byte [ ] data, String strFilename, String strContentType )
{
HttpServletResponse response = _response;
OutputStream os;
MVCUtils.addDownloadHeaderToResponse( response, strFilename, strContentType );
try
{
os = response.getOutputStream( );
os.write( data );
os.close( );
}
catch( IOException e )
{
AppLogService.error( e.getStackTrace( ), e );
}
}
}