PageService.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.service.page;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.lang3.BooleanUtils;
import fr.paris.lutece.portal.business.page.Page;
import fr.paris.lutece.portal.business.page.PageHome;
import fr.paris.lutece.portal.business.page.PageRoleRemovalListener;
import fr.paris.lutece.portal.business.portlet.Portlet;
import fr.paris.lutece.portal.business.portlet.PortletRoleRemovalListener;
import fr.paris.lutece.portal.business.portlet.PortletType;
import fr.paris.lutece.portal.business.style.ModeHome;
import fr.paris.lutece.portal.business.user.AdminUser;
import fr.paris.lutece.portal.service.admin.AdminUserService;
import fr.paris.lutece.portal.service.cache.ICacheKeyService;
import fr.paris.lutece.portal.service.content.PageData;
import fr.paris.lutece.portal.service.html.XmlTransformerService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.image.ImageResource;
import fr.paris.lutece.portal.service.image.ImageResourceManager;
import fr.paris.lutece.portal.service.image.ImageResourceProvider;
import fr.paris.lutece.portal.service.includes.PageInclude;
import fr.paris.lutece.portal.service.includes.PageIncludeService;
import fr.paris.lutece.portal.service.message.SiteMessageException;
import fr.paris.lutece.portal.service.portal.PortalService;
import fr.paris.lutece.portal.service.portal.ThemesService;
import fr.paris.lutece.portal.service.portlet.PortletEvent;
import fr.paris.lutece.portal.service.portlet.PortletEventListener;
import fr.paris.lutece.portal.service.portlet.PortletResourceIdService;
import fr.paris.lutece.portal.service.rbac.RBACService;
import fr.paris.lutece.portal.service.security.LuteceUser;
import fr.paris.lutece.portal.service.security.SecurityService;
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.AppPathService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.portal.service.util.RemovalListenerService;
import fr.paris.lutece.portal.web.LocalVariables;
import fr.paris.lutece.portal.web.constants.Parameters;
import fr.paris.lutece.portal.web.l10n.LocaleService;
import fr.paris.lutece.util.html.HtmlTemplate;
import fr.paris.lutece.util.url.UrlItem;
/**
* This class delivers pages to web componants. It handles XML tranformation to HTML and provides a cache feature in order to reduce the number of
* tranformations.
*/
public class PageService implements IPageService, ImageResourceProvider, PageEventListener, PortletEventListener
{
// //////////////////////////////////////////////////////////////////////////
// Variables
/**
* Key for redirections
*/
public static final String REDIRECTION_KEY = "redirect:";
// Templates
/** Access denied template */
public static final String TEMPLATE_PAGE_ACCESS_DENIED = "/skin/site/page_access_denied.html";
/** Access Controlled template */
public static final String TEMPLATE_PAGE_ACCESS_CONTROLED = "/skin/site/page_access_controled.html";
private static final String TEMPLATE_ADMIN_BUTTONS = "/admin/admin_buttons.html";
private static final String TEMPLATE_COLUMN_OUTLINE = "/admin/column_outline.html";
// Markers
private static final String MARK_PORTLET = "portlet";
private static final String MARK_STATUS_PUBLISHED = "portlet_status_published";
private static final String MARK_STATUS_UNPUBLISHED = "portlet_status_unpublished";
private static final String MARK_CUSTOM_ACTIONS = "custom_action_list";
private static final String MARK_URL_LOGIN = "url_login";
private static final String MARKER_TARGET = "target";
private static final String MARKER_IS_USER_AUTHENTICATED = "is-user-authenticated";
private static final String MARK_COLUMN_CONTENT = "column_content";
private static final String MARK_COLUMN_ID = "column_id";
private static final String MARK_MAX_ORDER = "order_max";
// Parameters
private static final String PARAMETER_SITE_PATH = "site-path";
private static final String PARAMETER_USER_SELECTED_LOCALE = "user-selected-language";
private static final String PARAMETER_PLUGIN_NAME = "plugin-name";
private static final String PARAMETER_PORTLET = "portlet";
// Properties
private static final String PROPERTY_MESSAGE_PAGE_ACCESS_DENIED = "portal.site.message.pageAccessDenied";
private static final String CONTENT_SERVICE_NAME = "PageService";
private static final String PROPERTY_COLUMN_MAX = "nb.columns";
private static final int DEFAULT_COLUMN_MAX = 5;
private static final int DEFAULT_PORTLET_ORDER_MAX = 15;
private static final String KEY_THEME = "theme";
private static final String TARGET_TOP = "target='_top'";
private static final String WELCOME_PAGE_ID = "1";
private static final String WELCOME_PAGE_CACHE_KEY = "mode0";
private static final int MODE_ADMIN = 1;
private static final String VALUE_TRUE = "1";
private static final String VALUE_FALSE = "0";
private static final String XSL_UNIQUE_PREFIX = "page-";
private static final String ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED = "core.canPageBeCached";
private static final String DEFAULT_OPEN_TAG_PREFIX = "<div class=\"lutece-admin-portlet\" draggable=\"true\">";
private static final String DEFAULT_CLOSE_TAG_PREFIX = "</div>";
private static final String ADMIN_PORTLET_OPEN_TAG = AppPropertiesService.getProperty( "lutece.portlet.open.tag", DEFAULT_OPEN_TAG_PREFIX );
private static final String ADMIN_PORTLET_CLOSE_TAG = AppPropertiesService.getProperty( "lutece.portlet.close.tag", DEFAULT_CLOSE_TAG_PREFIX );
private static final int PORTLET_MAX_ORDER = AppPropertiesService.getPropertyInt( "lutece.list.order.max", DEFAULT_PORTLET_ORDER_MAX );
// Specific for plugin-document
private static final String DOCUMENT_LIST_PORTLET = "DOCUMENT_LIST_PORTLET";
private static final String DOCUMENT_PORTLET = "DOCUMENT_PORTLET";
private static final String DOCUMENT_ACTION_URL = "jsp/admin/plugins/document/ManagePublishing.jsp";
private static final String DOCUMENT_IMAGE_URL = "images/admin/skin/actions/publish.png";
private static final String DOCUMENT_TITLE = "portal.site.portletPreview.buttonManage";
private static final int MAX_COLUMNS = AppPropertiesService.getPropertyInt( PROPERTY_COLUMN_MAX, DEFAULT_COLUMN_MAX );
private static List<PageEventListener> _listEventListeners = new ArrayList<>( );
private ICacheKeyService _cksPage;
private ICacheKeyService _cksPortlet;
private PageCacheService _cachePages;
private PortletCacheService _cachePortlets;
/**
* Creates a new PageService object.
*
* @param pageCacheService
* the page cache service
* @param portletCacheService
* the portlet cache service
*/
@Inject
public PageService( PageCacheService pageCacheService, PortletCacheService portletCacheService )
{
_cachePages = pageCacheService;
_cachePortlets = portletCacheService;
init( );
}
/**
* Initializes the service
*/
private void init( )
{
_cachePages.initCache( );
_cachePortlets.initCache( );
ImageResourceManager.registerProvider( this );
addPageEventListener( this );
}
/**
* Returns the Content Service name
*
* @return The name as a String
*/
public String getName( )
{
return CONTENT_SERVICE_NAME;
}
/**
* Returns the page for a given ID. The page is built using XML data of each portlet or retrieved from the cache if it's enable.
*
* @param request
* The page ID
* @param nMode
* The current mode.
* @return The HTML code of the page as a String.
* @throws SiteMessageException
* If a message shouldbe displayed
*/
@Override
public String getPage( HttpServletRequest request, int nMode ) throws SiteMessageException
{
String strPageId = request.getParameter( Parameters.PAGE_ID );
return getPage( strPageId, nMode, request );
}
/**
* Returns the page for a given ID. The page is built using XML data of each portlet or retrieved from the cache if it's enable.
*
* @param strIdPage
* The page ID
* @param nMode
* The current mode.
* @param request
* The HttpRequest
* @return The HTML code of the page as a String.
* @throws SiteMessageException
* occurs when a site message need to be displayed
*/
@Override
public String getPage( String strIdPage, int nMode, HttpServletRequest request ) throws SiteMessageException
{
try
{
String strPage;
// The cache is enable !
if ( _cachePages.isCacheEnable( ) )
{
strPage = getCachedPage( strIdPage, nMode, request );
// redirection handling
strPage = redirect( strPage );
}
else
{
strPage = buildPageContent( strIdPage, nMode, request );
}
return strPage;
}
catch( NumberFormatException nfe )
{
AppLogService.error( "PageService.getPage() : {}", nfe.getLocalizedMessage( ), nfe );
throw new PageNotFoundException( );
}
}
private String redirect( String strPage )
{
if ( strPage.startsWith( REDIRECTION_KEY ) )
{
strPage = strPage.replaceFirst( REDIRECTION_KEY, "" );
try
{
LocalVariables.getResponse( ).sendRedirect( strPage );
}
catch( IOException e )
{
AppLogService.error( "Error on sendRedirect for {}", strPage );
}
}
return strPage;
}
private String getCachedPage( String strIdPage, int nMode, HttpServletRequest request ) throws SiteMessageException
{
// Get request paramaters and store them in a HashMap
Map<String, String> htParamRequest = readRequestParams( request, strIdPage );
LuteceUser user = SecurityService.getInstance( ).getRegisteredUser( request );
// we add the key in the memory key only if cache is enable
String strKey = getKey( htParamRequest, nMode, user );
// get page from cache
String strPage = (String) _cachePages.getFromCache( strKey );
if ( strPage == null )
{
// only one thread can evaluate the page
synchronized( strKey )
{
// can be useful if an other thread had evaluate the
// page
strPage = (String) _cachePages.getFromCache( strKey );
// ignore checkstyle, this double verification is useful
// when page cache has been created when thread is
// blocked on synchronized
if ( strPage == null )
{
boolean bCanBeCached = true;
AppLogService.debug( "Page generation {}", strKey );
RedirectionResponseWrapper response = new RedirectionResponseWrapper( LocalVariables.getResponse( ) );
LocalVariables.setLocal( LocalVariables.getConfig( ), LocalVariables.getRequest( ), response );
request.setAttribute( ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED, null );
// The key is not in the cache, so we have to build
// the page
strPage = buildPageContent( strIdPage, nMode, request );
// We check if the page contains portlets that can not be cached.
if ( Boolean.FALSE.equals( request.getAttribute( ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED ) ) )
{
bCanBeCached = false;
}
if ( response.getRedirectLocation( ) != null )
{
AppLogService.debug( "Redirection found {}", response.getRedirectLocation( ) );
strPage = REDIRECTION_KEY + response.getRedirectLocation( );
}
// Add the page to the cache if the page can be
// cached
if ( bCanBeCached && ( nMode != MODE_ADMIN ) )
{
_cachePages.putInCache( strKey, strPage );
}
}
else
{
AppLogService.debug( "Page read from cache after synchronisation {}", strKey );
}
}
}
else
{
AppLogService.debug( "Page read from cache {}", strKey );
}
return strPage;
}
private Map<String, String> readRequestParams( HttpServletRequest request, String strIdPage )
{
Enumeration<?> enumParam = request.getParameterNames( );
Map<String, String> htParamRequest = new HashMap<>( );
while ( enumParam.hasMoreElements( ) )
{
String paramName = (String) enumParam.nextElement( );
htParamRequest.put( paramName, request.getParameter( paramName ) );
}
if ( !htParamRequest.containsKey( Parameters.PAGE_ID ) )
{
htParamRequest.put( Parameters.PAGE_ID, strIdPage );
}
if ( !htParamRequest.containsKey( Parameters.BASE_URL ) )
{
htParamRequest.put( Parameters.BASE_URL, AppPathService.getBaseUrl( request ) );
}
String strUserTheme = ThemesService.getUserTheme( request );
if ( strUserTheme != null )
{
htParamRequest.put( KEY_THEME, strUserTheme );
}
return htParamRequest;
}
/**
* Build the page content.
*
* @param strIdPage
* The page ID
* @param nMode
* The current mode.
* @param request
* The HttpRequest
* @return The HTML code of the page as a String.
* @throws SiteMessageException
* occurs when a site message need to be displayed
*/
public String buildPageContent( String strIdPage, int nMode, HttpServletRequest request ) throws SiteMessageException
{
int nIdPage;
Page page;
nIdPage = Integer.parseInt( strIdPage );
boolean bPageExist = PageHome.checkPageExist( nIdPage );
if ( bPageExist )
{
page = PageHome.getPage( nIdPage );
}
else
{
// If there is a problem finding the page, returns the home page
nIdPage = PortalService.getRootPageId( );
page = PageHome.getPage( nIdPage );
}
PageData data = new PageData( );
data.setName( page.getName( ) );
data.setPagePath( PortalService.getPagePathContent( nIdPage, nMode, request ) );
data.setTheme( page.getCodeTheme( ) );
data.setMetaKeywords( page.getMetaKeywords( ) );
data.setMetaDescription( page.getMetaDescription( ) );
data.setDisplayDateUpdate( page.getDisplayDateUpdate( ) );
data.setDateUpdate( page.getDateUpdate( ) );
// Checks the page role (v1.1)
String strRole = page.getRole( );
if ( !strRole.equals( Page.ROLE_NONE ) && ( SecurityService.isAuthenticationEnable( ) ) && ( nMode != MODE_ADMIN ) )
{
LuteceUser user = SecurityService.getInstance( ).getRegisteredUser( request );
if ( ( user == null ) && ( !SecurityService.getInstance( ).isExternalAuthentication( ) ) )
{
// The user is not registered and identify itself with the
// Portal authentication
String strAccessControledTemplate = SecurityService.getInstance( ).getAccessControledTemplate( );
HashMap<String, Object> model = new HashMap<>( );
String strLoginUrl = SecurityService.getInstance( ).getLoginPageUrl( );
model.put( MARK_URL_LOGIN, strLoginUrl );
HtmlTemplate tAccessControled = AppTemplateService.getTemplate( strAccessControledTemplate, request.getLocale( ), model );
data.setContent( tAccessControled.getHtml( ) );
return PortalService.buildPageContent( nIdPage, data, nMode, request );
}
if ( !SecurityService.getInstance( ).isUserInRole( request, strRole ) )
{
// The user doesn't have the correct role
String strAccessDeniedTemplate = SecurityService.getInstance( ).getAccessDeniedTemplate( );
HtmlTemplate tAccessDenied = AppTemplateService.getTemplate( strAccessDeniedTemplate, request.getLocale( ) );
data.setContent( tAccessDenied.getHtml( ) );
return PortalService.buildPageContent( nIdPage, data, nMode, request );
}
}
// Added in v2.0
// Add the page authorization
if ( nMode == MODE_ADMIN )
{
AdminUser user = AdminUserService.getAdminUser( request );
if ( isAuthorizedAdminPage( nIdPage, PageResourceIdService.PERMISSION_VIEW, user ) )
{
// Fill a PageData structure for those elements
data.setContent( getPageContent( nIdPage, nMode, request ) );
}
else
{
data.setContent( I18nService.getLocalizedString( PROPERTY_MESSAGE_PAGE_ACCESS_DENIED, user.getLocale( ) ) );
}
}
else
{
data.setContent( getPageContent( nIdPage, nMode, request ) );
}
if ( nIdPage == PortalService.getRootPageId( ) )
{
// This page is the home page.
data.setHomePage( true );
}
return PortalService.buildPageContent( nIdPage, data, nMode, request );
}
/**
* Build the page content.
*
* @param nIdPage
* The page ID
* @param nMode
* The current mode.
* @param request
* The HttpRequest
* @return The HTML code of the page as a String.
* @throws SiteMessageException
* occurs when a site message need to be displayed
*/
@Override
public String getPageContent( int nIdPage, int nMode, HttpServletRequest request ) throws SiteMessageException
{
Locale locale = Optional.ofNullable( request ).map( HttpServletRequest::getLocale ).orElse( LocaleService.getDefault( ) );
String [ ] arrayContent = new String [ MAX_COLUMNS];
for ( int i = 0; i < MAX_COLUMNS; i++ )
{
arrayContent [i] = "";
}
Page page = PageHome.findByPrimaryKey( nIdPage );
Map<String, String> mapParams = getParams( request, nMode );
boolean bCanPageBeCached = Boolean.TRUE;
LuteceUser user = SecurityService.getInstance( ).getRegisteredUser( request );
for ( Portlet portlet : page.getPortlets( ) )
{
int nCol = portlet.getColumn( ) - 1;
if ( nCol < MAX_COLUMNS )
{
arrayContent [nCol] += getPortletContent( request, portlet, mapParams, nMode );
}
// We check if the portlet can be cached
if ( ( user != null ) ? ( !portlet.canBeCachedForConnectedUsers( ) ) : ( !portlet.canBeCachedForAnonymousUsers( ) ) )
{
bCanPageBeCached = false;
}
}
// Add columns outline in admin mode
if ( nMode == MODE_ADMIN )
{
for ( int i = 0; i < MAX_COLUMNS; i++ )
{
arrayContent [i] = addColumnOutline( i + 1, arrayContent [i], locale );
}
}
// We save that the page that is generating can not be cached
if ( !bCanPageBeCached && request != null )
{
request.setAttribute( ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED, false );
}
Map<String, Object> rootModel = new HashMap<>( );
for ( int j = 0; j < MAX_COLUMNS; j++ )
{
rootModel.put( "page_content_col" + ( j + 1 ), arrayContent [j] );
}
List<PageInclude> listIncludes = PageIncludeService.getIncludes( );
PageData data = new PageData( );
for ( PageInclude pic : listIncludes )
{
pic.fillTemplate( rootModel, data, nMode, request );
}
HtmlTemplate t = AppTemplateService.getTemplate( page.getTemplate( ), locale, rootModel );
return t.getHtml( );
}
/**
* Add the HTML code to display column outlines
*
* @param columnId
* the column id
* @param content
* the column content
* @param locale
* the locale
* @return The column code
*/
private String addColumnOutline( int columnId, String content, Locale locale )
{
Map<String, Object> model = new HashMap<>( 2 );
model.put( MARK_COLUMN_CONTENT, content );
model.put( MARK_COLUMN_ID, columnId );
HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_COLUMN_OUTLINE, locale, model );
return template.getHtml( );
}
/**
* Get the portlet content
*
* @param request
* The HTTP request
* @param portlet
* The portlet
* @param mapRequestParams
* request parameters
* @param nMode
* The mode
* @return The content
* @throws SiteMessageException
* If an error occurs
*/
private String getPortletContent( HttpServletRequest request, Portlet portlet, Map<String, String> mapRequestParams, int nMode ) throws SiteMessageException
{
if ( ( request != null ) && !isPortletVisible( request, portlet, nMode ) )
{
return StringUtils.EMPTY;
}
if ( request != null )
{
String strPluginName = portlet.getPluginName( );
request.setAttribute( PARAMETER_PLUGIN_NAME, strPluginName );
}
String strPortletContent = StringUtils.EMPTY;
// Add the admin buttons for portlet management on admin mode
if ( nMode == MODE_ADMIN )
{
strPortletContent = ADMIN_PORTLET_OPEN_TAG + addAdminButtons( request, portlet );
}
String strKey = StringUtils.EMPTY;
LuteceUser user = null;
if ( SecurityService.isAuthenticationEnable( ) )
{
user = SecurityService.getInstance( ).getRegisteredUser( request );
}
boolean isCacheEnabled = nMode != MODE_ADMIN && _cachePortlets.isCacheEnable( );
boolean bCanBeCached = user != null ? portlet.canBeCachedForConnectedUsers( ) : portlet.canBeCachedForAnonymousUsers( );
if ( portlet.isContentGeneratedByXmlAndXsl( ) )
{
Map<String, String> mapParams = mapRequestParams;
Map<String, String> mapXslParams = portlet.getXslParams( );
if ( mapParams != null )
{
if ( mapXslParams != null )
{
mapParams.putAll( mapXslParams );
}
}
else
{
mapParams = mapXslParams;
}
if ( isCacheEnabled && bCanBeCached )
{
mapParams.put( PARAMETER_PORTLET, String.valueOf( portlet.getId( ) ) );
strKey = _cksPortlet.getKey( mapParams, nMode, user );
String strPortlet = (String) _cachePortlets.getFromCache( strKey );
if ( strPortlet != null )
{
return strPortlet;
}
}
Properties outputProperties = ModeHome.getOuputXslProperties( nMode );
String strXslUniqueId = XSL_UNIQUE_PREFIX + String.valueOf( portlet.getStyleId( ) );
XmlTransformerService xmlTransformerService = new XmlTransformerService( );
String strPortletXmlContent = portlet.getXml( request );
strPortletContent += xmlTransformerService.transformBySourceWithXslCache( strPortletXmlContent, portlet.getXslSource( nMode ), strXslUniqueId, mapParams, outputProperties );
}
else
{
if ( isCacheEnabled && bCanBeCached )
{
mapRequestParams.put( PARAMETER_PORTLET, String.valueOf( portlet.getId( ) ) );
strKey = _cksPortlet.getKey( mapRequestParams, nMode, user );
String strPortlet = (String) _cachePortlets.getFromCache( strKey );
if ( strPortlet != null )
{
return strPortlet;
}
}
strPortletContent += portlet.getHtmlContent( request );
}
if ( isCacheEnabled && StringUtils.isNotEmpty( strKey ) )
{
_cachePortlets.putInCache( strKey, strPortletContent );
}
if ( nMode == MODE_ADMIN )
{
strPortletContent += ADMIN_PORTLET_CLOSE_TAG;
}
return strPortletContent;
}
private boolean isPortletVisible( HttpServletRequest request, Portlet portlet, int nMode )
{
if ( ( nMode != MODE_ADMIN ) && ( portlet.getStatus( ) == Portlet.STATUS_UNPUBLISHED ) )
{
return false;
}
String strRole = portlet.getRole( );
boolean bUserInRole = SecurityService.isAuthenticationEnable( ) ? SecurityService.getInstance( ).isUserInRole( request, strRole ) : true;
boolean [ ] conditions = new boolean [ ] {
strRole.equals( Page.ROLE_NONE ), // No role is required so the portlet is visible for anyone
!SecurityService.isAuthenticationEnable( ), // No authentication
nMode == MODE_ADMIN, // We are in Admin mode, so all the portlet should be visible
bUserInRole // The authentication is ON and the user get the role
};
return BooleanUtils.or( conditions );
}
/**
* Build the Cache HashMap key for pages Goal is to be able to have a synchronized on the key but a synchronize only work with strict reference. So we
* manage an hashmap of string reference for cache keys to be able to get them back.
*
* @param mapParams
* The Map params
* @param nMode
* The current mode.
* @param user
* Current Lutece user
* @return The HashMap key for articles pages as a String.
*/
private String getKey( Map<String, String> mapParams, int nMode, LuteceUser user )
{
String strKey = _cksPage.getKey( mapParams, nMode, user );
return _cachePages.getKey( strKey );
}
/**
* Remove a page from the cache
*
* @param nIdPage
* The page ID
*/
private void invalidatePage( int nIdPage )
{
String strIdPage = String.valueOf( nIdPage );
invalidatePage( strIdPage );
}
/**
* @param cacheKeyService
* the _cacheKeyService to set
*/
public void setPageCacheKeyService( ICacheKeyService cacheKeyService )
{
_cksPage = cacheKeyService;
}
/**
* @param cacheKeyService
* the _cacheKeyService to set
*/
public void setPortletCacheKeyService( ICacheKeyService cacheKeyService )
{
_cksPortlet = cacheKeyService;
}
/**
* @param removalService
* the removal listener service
*/
public void setRoleRemovalService( RemovalListenerService removalService )
{
removalService.registerListener( new PageRoleRemovalListener( ) );
removalService.registerListener( new PortletRoleRemovalListener( ) );
}
/**
* Remove a page from the cache
*
* @param strIdPage
* The page ID
*/
private void invalidatePage( String strIdPage )
{
if ( _cachePages.isCacheEnable( ) )
{
String strKey = "[" + Parameters.PAGE_ID + ":" + strIdPage + "]";
for ( String strKeyTemp : (List<String>) _cachePages.getCache( ).getKeys( ) )
{
if ( ( strKeyTemp.contains( strKey ) ) || ( WELCOME_PAGE_ID.equals( strIdPage ) && WELCOME_PAGE_CACHE_KEY.equals( strKeyTemp ) ) )
{
_cachePages.getCache( ).remove( strKeyTemp );
if ( AppLogService.isDebugEnabled( ) )
{
AppLogService.debug( "Page (cache key : " + strKeyTemp + ") removed from the cache." );
}
}
}
}
}
// ///////////////////////////////////////////////////////////////////////////
// Events Listeners management
/**
* Add a new page event listener
*
* @param listener
* An event listener to add
*/
public static void addPageEventListener( PageEventListener listener )
{
_listEventListeners.add( listener );
AppLogService.info( "New Page Event Listener registered : {}", listener.getClass( ).getName( ) );
}
/**
* Notify an event to all listeners
*
* @param event
* A page Event
*/
private void notifyListeners( PageEvent event )
{
for ( PageEventListener listener : _listEventListeners )
{
listener.processPageEvent( event );
}
}
/**
* Returns the resource type Id
*
* @return The resource type Id
*/
@Override
public String getResourceTypeId( )
{
return Page.IMAGE_RESOURCE_TYPE_ID;
}
/**
* Gets the image resource for a given resource
*
* @param nIdResource
* The Resource id
* @return The image resource
*/
@Override
public ImageResource getImageResource( int nIdResource )
{
return PageHome.getImageResource( nIdResource );
}
/**
* Create a page
*
* @param page
* The page to create
*/
@Override
public void createPage( Page page )
{
PageHome.create( page );
PageEvent event = new PageEvent( page, PageEvent.PAGE_CREATED );
notifyListeners( event );
}
/**
* Update a given page
*
* @param page
* The page to update
*/
@Override
public void updatePage( Page page )
{
PageHome.update( page );
PageEvent event = new PageEvent( page, PageEvent.PAGE_CONTENT_MODIFIED );
notifyListeners( event );
}
/**
* Remove a given page
*
* @param nPageId
* The page Id
*/
@Override
public void removePage( int nPageId )
{
Page page = PageHome.findByPrimaryKey( nPageId );
PageEvent event = new PageEvent( page, PageEvent.PAGE_DELETED );
PageHome.remove( nPageId );
notifyListeners( event );
}
/**
* Process a page event
*
* @param event
* The event to process
*/
@Override
public void processPageEvent( PageEvent event )
{
Page page = event.getPage( );
invalidatePage( page.getId( ) );
}
/**
* {@inheritDoc}
*/
@Override
public void processPortletEvent( PortletEvent event )
{
invalidateContent( event.getPageId( ) );
}
/**
* Invalidate Page Content
*
* @param nPageId
* The Page ID
*/
@Override
public void invalidateContent( int nPageId )
{
Page page = PageHome.findByPrimaryKey( nPageId );
PageEvent event = new PageEvent( page, PageEvent.PAGE_CONTENT_MODIFIED );
notifyListeners( event );
}
/**
* Check that a given user is allowed to access a page for a given permission
*
* @param nIdPage
* the id of the page to check
* @param strPermission
* the permission needed
* @param user
* The current user
* @return true if authorized, otherwise false
*/
@Override
public boolean isAuthorizedAdminPage( int nIdPage, String strPermission, AdminUser user )
{
Page page = PageHome.findByPrimaryKey( nIdPage );
if ( page.getIdAuthorizationNode( ) != null )
{
String strAuthorizationNode = Integer.toString( page.getIdAuthorizationNode( ) );
return ( RBACService.isAuthorized( Page.RESOURCE_TYPE, strAuthorizationNode, strPermission, user ) );
}
return true;
}
/**
* Add the HTML code to display admin buttons under each portlet
*
* @param request
* The Http request
* @param portlet
* The portlet
* @return The buttons code
*/
private String addAdminButtons( HttpServletRequest request, Portlet portlet )
{
AdminUser user = AdminUserService.getAdminUser( request );
if ( RBACService.isAuthorized( PortletType.RESOURCE_TYPE, portlet.getPortletTypeId( ), PortletResourceIdService.PERMISSION_MANAGE, user ) )
{
Locale locale = user.getLocale( );
Collection<PortletCustomAdminAction> listCustomActions = new ArrayList<>( );
// TODO : listCustomActions should be provided by PortletType
// FIXME : Delete plugin-document specifics
if ( portlet.getPortletTypeId( ).equals( DOCUMENT_LIST_PORTLET ) || portlet.getPortletTypeId( ).equals( DOCUMENT_PORTLET ) )
{
PortletCustomAdminAction customAction = new PortletCustomAdminAction( );
customAction.setActionUrl( DOCUMENT_ACTION_URL );
customAction.setImageUrl( DOCUMENT_IMAGE_URL );
customAction.setTitle( DOCUMENT_TITLE );
listCustomActions.add( customAction );
}
Map<String, Object> model = new HashMap<>( );
model.put( MARK_PORTLET, portlet );
model.put( MARK_STATUS_PUBLISHED, Portlet.STATUS_PUBLISHED );
model.put( MARK_MAX_ORDER, PORTLET_MAX_ORDER );
model.put( MARK_STATUS_UNPUBLISHED, Portlet.STATUS_UNPUBLISHED );
model.put( MARK_CUSTOM_ACTIONS, listCustomActions );
HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_ADMIN_BUTTONS, locale, model );
return template.getHtml( );
}
return StringUtils.EMPTY;
}
/**
* Gets the params map
*
* @param request
* The HTTP request
* @param nMode
* The mode
* @return the map
*/
private Map<String, String> getParams( HttpServletRequest request, int nMode )
{
Map<String, String> mapModifyParam = new HashMap<>( );
String strParamName;
// Get request paramaters and store them in a HashMap
if ( request != null )
{
Enumeration<?> enumParam = request.getParameterNames( );
while ( enumParam.hasMoreElements( ) )
{
strParamName = (String) enumParam.nextElement( );
mapModifyParam.put( strParamName, request.getParameter( strParamName ) );
}
// Add selected locale
mapModifyParam.put( PARAMETER_USER_SELECTED_LOCALE, LocaleService.getUserSelectedLocale( request ).getLanguage( ) );
}
// Added in v1.3
// Add a path param for choose url to use in admin or normal mode
if ( nMode != MODE_ADMIN )
{
mapModifyParam.put( PARAMETER_SITE_PATH, AppPathService.getPortalUrl( ) );
if ( SecurityService.isAuthenticationEnable( ) )
{
mapModifyParam.put( MARKER_IS_USER_AUTHENTICATED,
( SecurityService.getInstance( ).getRegisteredUser( request ) != null ) ? VALUE_TRUE : VALUE_FALSE );
}
}
else
{
mapModifyParam.put( PARAMETER_SITE_PATH, AppPathService.getAdminPortalUrl( ) );
mapModifyParam.put( MARKER_TARGET, TARGET_TOP );
}
if ( !mapModifyParam.containsKey( Parameters.PAGE_ID ) )
{
mapModifyParam.put( Parameters.PAGE_ID, Integer.toString( PortalService.getRootPageId( ) ) );
}
return mapModifyParam;
}
/**
* Management of the image associated to the page
*
* @param strPageId
* The page identifier
* @return The url
*/
public String getResourceImagePage( String strPageId )
{
String strResourceType = getResourceTypeId( );
UrlItem url = new UrlItem( Parameters.IMAGE_SERVLET );
url.addParameter( Parameters.RESOURCE_TYPE, strResourceType );
url.addParameter( Parameters.RESOURCE_ID, strPageId );
return url.getUrlWithEntity( );
}
/**
* Gets the page cache service.
*
* @return the page cache service
*/
public PageCacheService getPageCacheService( )
{
return _cachePages;
}
/**
* Sets the cache page service
*
* @param pageCacheService
* the page cache service
*/
public void setPageCacheService( PageCacheService pageCacheService )
{
_cachePages = pageCacheService;
}
/**
* Gets the portlet cache service
*
* @return the porlet cache service
*/
public PortletCacheService getPortletCacheService( )
{
return _cachePortlets;
}
/**
* Gets the portlet cache service
*
* @param portletCacheService
* the portlet cache service
*/
public void setPortletCacheService( PortletCacheService portletCacheService )
{
_cachePortlets = portletCacheService;
}
/**
* update authorization node of children page
*
* @param nIdParentPage
* id of the parent page
* @param nIdNewAuthorizationNode
* the new authorization id
*/
public static void updateChildrenAuthorizationNode( int nIdParentPage, Integer nIdNewAuthorizationNode )
{
List<Integer> listPagesChildren = PageHome.getPagesWhichMustChangeAuthorizationNode( nIdParentPage );
if ( listPagesChildren != null )
{
for ( Integer idPage : listPagesChildren )
{
PageHome.updateAuthorizationNode( idPage, nIdNewAuthorizationNode );
updateChildrenAuthorizationNode( idPage, nIdNewAuthorizationNode );
}
}
}
}