XPageAppService.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.content;
- import fr.paris.lutece.portal.service.init.LuteceInitException;
- import fr.paris.lutece.portal.service.message.SiteMessage;
- import fr.paris.lutece.portal.service.message.SiteMessageException;
- import fr.paris.lutece.portal.service.message.SiteMessageService;
- import fr.paris.lutece.portal.service.portal.PortalService;
- 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.spring.SpringContextService;
- 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.web.xpages.XPage;
- import fr.paris.lutece.portal.web.xpages.XPageApplication;
- import fr.paris.lutece.portal.web.xpages.XPageApplicationEntry;
- import fr.paris.lutece.util.html.HtmlTemplate;
- import fr.paris.lutece.util.http.SecurityUtil;
- import org.apache.commons.collections.CollectionUtils;
- import org.springframework.beans.factory.NoSuchBeanDefinitionException;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- /**
- * This class delivers Extra pages (xpages) to web components. An XPage is a page where the content is provided by a specific class, but should be integrated
- * into the portal struture and design. XPageApps are identified by a key name. To display an XPage into the portal just call the following url :<br>
- * <code>
- * Portal.jsp?page=<i>keyname</i>&param1=value1& ...&paramN=valueN </code>
- *
- * @see fr.paris.lutece.portal.web.xpages.XPage
- */
- public class XPageAppService extends ContentService
- {
- public static final String PARAM_XPAGE_APP = "page";
- private static final String ERROR_INSTANTIATION = "Error instantiating XPageApplication : ";
- private static final String CONTENT_SERVICE_NAME = "XPageAppService";
- private static final String MESSAGE_ERROR_APP_BODY = "portal.util.message.errorXpageApp";
- private static final String ATTRIBUTE_XPAGE = "LUTECE_XPAGE_";
- private static Map<String, XPageApplicationEntry> _mapApplications = new HashMap<>( );
- /**
- * Register an application by its entry defined in the plugin xml file
- *
- * @param entry
- * The application entry
- * @throws LuteceInitException
- * If an error occured
- */
- public static void registerXPageApplication( XPageApplicationEntry entry ) throws LuteceInitException
- {
- try
- {
- if ( entry.getClassName( ) == null )
- {
- String applicationBeanName = entry.getPluginName( ) + ".xpage." + entry.getId( );
- if ( !SpringContextService.getContext( ).containsBean( applicationBeanName ) )
- {
- throw new LuteceInitException( ERROR_INSTANTIATION + entry.getId( ) + " - Could not find bean named " + applicationBeanName,
- new NoSuchBeanDefinitionException( applicationBeanName ) );
- }
- }
- else
- {
- // check that the class can be found
- Class.forName( entry.getClassName( ) ).newInstance( );
- }
- _mapApplications.put( entry.getId( ), entry );
- AppLogService.info( "New XPage application registered : {} {}", entry::getId, ( ) -> ( entry.isEnabled( ) ? "" : " (disabled)" ) );
- }
- catch( ClassNotFoundException | InstantiationException | IllegalAccessException e )
- {
- throw new LuteceInitException( ERROR_INSTANTIATION + entry.getId( ) + " - " + e.getCause( ), e );
- }
- }
- /**
- * Returns the Content Service name
- *
- * @return The name as a String
- */
- @Override
- public String getName( )
- {
- return CONTENT_SERVICE_NAME;
- }
- /**
- * Analyzes request parameters to see if the request should be handled by the current Content Service
- *
- * @param request
- * The HTTP request
- * @return true if this ContentService should handle this request
- */
- @Override
- public boolean isInvoked( HttpServletRequest request )
- {
- String strXPage = request.getParameter( PARAM_XPAGE_APP );
- return ( strXPage != null ) && ( strXPage.length( ) > 0 );
- }
- /**
- * Gets the current cache status.
- *
- * @return true if enable, otherwise false
- */
- @Override
- public boolean isCacheEnable( )
- {
- return false;
- }
- /**
- * Reset the cache.
- */
- @Override
- public void resetCache( )
- {
- // Do nothing
- }
- /**
- * Gets the number of item currently in the cache.
- *
- * @return the number of item currently in the cache.
- */
- @Override
- public int getCacheSize( )
- {
- return 0;
- }
- /**
- * Build the XPage content.
- *
- * @param request
- * The HTTP request.
- * @param nMode
- * The current mode.
- * @return The HTML code of the page.
- * @throws UserNotSignedException
- * The User Not Signed Exception
- * @throws SiteMessageException
- * occurs when a site message need to be displayed
- */
- @Override
- public String getPage( HttpServletRequest request, int nMode ) throws UserNotSignedException, SiteMessageException
- {
- // Gets XPage info from the lutece.properties
- String strName = request.getParameter( PARAM_XPAGE_APP );
- XPageApplicationEntry entry = getApplicationEntry( strName );
- // TODO : Handle entry == null
- if ( ( entry == null ) || ( !entry.isEnable( ) ) )
- {
- AppLogService.error( "The specified Xpage '{}' cannot be retrieved. Check installation of your Xpage application.",
- ( ) -> SecurityUtil.logForgingProtect( strName ) );
- SiteMessageService.setMessage( request, MESSAGE_ERROR_APP_BODY, SiteMessage.TYPE_ERROR );
- return null; // unreachable because SiteMessageService.setMessage throws
- }
- XPage page = null;
- List<String> listRoles = entry.getRoles( );
- if ( SecurityService.isAuthenticationEnable( ) && CollectionUtils.isNotEmpty( listRoles ) )
- {
- LuteceUser user = SecurityService.getInstance( ).getRegisteredUser( request );
- if ( user == null )
- {
- throw new UserNotSignedException( );
- }
- boolean bAutorized = SecurityService.getInstance( ).isUserInAnyRole( request, listRoles );
- if ( bAutorized )
- {
- XPageApplication application = getXPageSessionInstance( request, entry );
- page = application.getPage( request, nMode, entry.getPlugin( ) );
- }
- else
- {
- // The user doesn't have the correct role
- String strAccessDeniedTemplate = SecurityService.getInstance( ).getAccessDeniedTemplate( );
- HtmlTemplate tAccessDenied = AppTemplateService.getTemplate( strAccessDeniedTemplate );
- page = new XPage( );
- page.setContent( tAccessDenied.getHtml( ) );
- }
- }
- else
- {
- XPageApplication application = getXPageSessionInstance( request, entry );
- page = application.getPage( request, nMode, entry.getPlugin( ) );
- }
- if ( page.isStandalone( ) || page.isSendRedirect() )
- {
- return page.getContent( );
- }
- PageData data = new PageData( );
- data.setContent( page.getContent( ) );
- data.setName( page.getTitle( ) );
- // set the page path. Done by adding the extra-path information to the
- // pathLabel.
- String strXml = page.getXmlExtendedPathLabel( );
- if ( strXml == null )
- {
- data.setPagePath( PortalService.getXPagePathContent( page.getPathLabel( ), 0, request ) );
- }
- else
- {
- data.setPagePath( PortalService.getXPagePathContent( page.getPathLabel( ), 0, strXml, request ) );
- }
- return PortalService.buildPageContent( data, nMode, request );
- }
- /**
- * Gets Application entry by name
- *
- * @param strName
- * The application's name
- * @return The entry
- */
- public static XPageApplicationEntry getApplicationEntry( String strName )
- {
- return _mapApplications.get( strName );
- }
- /**
- * Gets applications list
- *
- * @return A collection of applications
- */
- public static Collection<XPageApplicationEntry> getXPageApplicationsList( )
- {
- return _mapApplications.values( );
- }
- /**
- * Return an instance of the XPage attached to the current Http Session
- *
- * @param request
- * The HTTP request
- * @param entry
- * The XPage entry
- * @return The XPage instance
- */
- private static XPageApplication getXPageSessionInstance( HttpServletRequest request, XPageApplicationEntry entry )
- {
- HttpSession session = request.getSession( true );
- String strAttribute = ATTRIBUTE_XPAGE + entry.getId( );
- XPageApplication application = (XPageApplication) session.getAttribute( strAttribute );
- if ( application == null )
- {
- application = getApplicationInstance( entry );
- session.setAttribute( strAttribute, application );
- AppLogService.debug( "New XPage instance of {} created and attached to session {}", entry.getClassName( ), session );
- }
- return application;
- }
- /**
- * Get an XPage instance
- *
- * @param entry
- * The Xpage entry
- * @return An instance of a given XPage
- */
- public static XPageApplication getApplicationInstance( XPageApplicationEntry entry )
- {
- XPageApplication application = null;
- try
- {
- if ( entry.getClassName( ) == null )
- {
- application = SpringContextService.getBean( entry.getPluginName( ) + ".xpage." + entry.getId( ) );
- }
- else
- {
- application = (XPageApplication) Class.forName( entry.getClassName( ) ).newInstance( );
- }
- }
- catch( Exception e )
- {
- throw new AppException( ERROR_INSTANTIATION + entry.getId( ) + " - " + e.getCause( ), e );
- }
- return application;
- }
- }