PortalMenuService.java

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

  35. import fr.paris.lutece.portal.business.XmlContent;
  36. import fr.paris.lutece.portal.business.page.Page;
  37. import fr.paris.lutece.portal.business.page.PageHome;
  38. import fr.paris.lutece.portal.business.portalcomponent.PortalComponentHome;
  39. import fr.paris.lutece.portal.business.style.ModeHome;
  40. import fr.paris.lutece.portal.business.stylesheet.StyleSheet;
  41. import fr.paris.lutece.portal.service.cache.AbstractCacheableService;
  42. import fr.paris.lutece.portal.service.html.XmlTransformerService;
  43. import fr.paris.lutece.portal.service.page.PageEvent;
  44. import fr.paris.lutece.portal.service.page.PageEventListener;
  45. import fr.paris.lutece.portal.service.page.PageService;
  46. import fr.paris.lutece.portal.service.security.LuteceUser;
  47. import fr.paris.lutece.portal.service.security.SecurityService;
  48. import fr.paris.lutece.util.xml.XmlUtil;

  49. import org.apache.commons.lang3.StringUtils;

  50. import java.util.Arrays;
  51. import java.util.Collection;
  52. import java.util.HashMap;
  53. import java.util.Map;
  54. import java.util.Properties;

  55. import javax.servlet.http.HttpServletRequest;

  56. /**
  57.  * This Service build the portal menu
  58.  */
  59. public final class PortalMenuService extends AbstractCacheableService implements PageEventListener
  60. {
  61.     public static final int MENU_INIT = 0;
  62.     public static final int MENU_MAIN = 1;
  63.     public static final int MODE_NORMAL = 0;
  64.     public static final int MODE_ADMIN = 1;
  65.     private static final int PORTAL_COMPONENT_MENU_INIT_ID = 3;
  66.     private static final int PORTAL_COMPONENT_MAIN_MENU_ID = 4;
  67.     private static final String SERVICE_NAME = "PortalMenuService";

  68.     // Menus cache
  69.     private static PortalMenuService _singleton;

  70.     /** Creates a new instance of PortalMenuService */
  71.     private PortalMenuService( )
  72.     {
  73.         initCache( getName( ) );
  74.         PageService.addPageEventListener( this );
  75.     }

  76.     /**
  77.      * Get the unique instance of the service
  78.      *
  79.      * @return The unique instance
  80.      */
  81.     public static synchronized PortalMenuService getInstance( )
  82.     {
  83.         if ( _singleton == null )
  84.         {
  85.             _singleton = new PortalMenuService( );
  86.         }

  87.         return _singleton;
  88.     }

  89.     /**
  90.      * Returns the service name
  91.      *
  92.      * @return The service name
  93.      */
  94.     public String getName( )
  95.     {
  96.         return SERVICE_NAME;
  97.     }

  98.     /**
  99.      * Returns the menu bar from the cache or builds it if it not stored in it
  100.      *
  101.      * @param request
  102.      *            The HTTP request
  103.      * @param nMode
  104.      *            The selected mode
  105.      * @param nPart
  106.      *            The part of the menu to build
  107.      * @param nCurrentPageId
  108.      *            The current page ID
  109.      * @return The list of the menus layed out with the stylesheet correpsonding to the mode
  110.      */
  111.     public String getMenuContent( int nCurrentPageId, int nMode, int nPart, HttpServletRequest request )
  112.     {
  113.         String strKey = getKey( nMode, nPart, request );
  114.         String strMenu = (String) getFromCache( strKey );

  115.         // Seek for the key in the cache
  116.         if ( strMenu == null )
  117.         {
  118.             // Builds the HTML document
  119.             strMenu = buildMenuContent( nCurrentPageId, nMode, nPart, request );

  120.             // Add it in the cache
  121.             putInCache( strKey, strMenu );

  122.             return strMenu;
  123.         }

  124.         // The document exist in the cache
  125.         return strMenu;
  126.     }

  127.     /**
  128.      * Builds the menu bar
  129.      *
  130.      * @param nCurrentPageId
  131.      *            The current page ID
  132.      * @param nMode
  133.      *            The selected mode
  134.      * @param nPart
  135.      *            The part of the menu to build
  136.      * @param request
  137.      *            The HttpServletRequest
  138.      * @return The list of the menus layed out with the stylesheet of the mode
  139.      */
  140.     private String buildMenuContent( int nCurrentPageId, int nMode, int nPart, HttpServletRequest request )
  141.     {
  142.         Collection<Page> listPagesMenu = PageHome.getChildPagesMinimalData( PortalService.getRootPageId( ) );

  143.         StringBuffer strXml = new StringBuffer( );
  144.         strXml.append( XmlUtil.getXmlHeader( ) );
  145.         XmlUtil.beginElement( strXml, XmlContent.TAG_MENU_LIST );

  146.         int nMenuIndex = 1;

  147.         for ( Page menuPage : listPagesMenu )
  148.         {
  149.             if ( ( menuPage.isVisible( request ) ) || ( nMode == MODE_ADMIN ) )
  150.             {
  151.                 buildPageXml( menuPage, strXml, nMode, nMenuIndex, nCurrentPageId, request );

  152.                 nMenuIndex++;
  153.             }
  154.         }

  155.         XmlUtil.endElement( strXml, XmlContent.TAG_MENU_LIST );

  156.         // Added in v1.3
  157.         StyleSheet xslSource = getMenuXslSource( nMode, nPart );

  158.         Properties outputProperties = ModeHome.getOuputXslProperties( nMode );

  159.         // Added in v1.3
  160.         // Add a path param for choose url to use in admin or normal mode
  161.         Map<String, String> mapParamRequest = new HashMap<>( );
  162.         PortalService.setXslPortalPath( mapParamRequest, nMode );

  163.         XmlTransformerService xmlTransformerService = new XmlTransformerService( );

  164.         return xmlTransformerService.transformBySourceWithXslCache( strXml.toString( ), xslSource, mapParamRequest, outputProperties );
  165.     }

  166.     private void buildPageXml( Page menuPage, StringBuffer strXml, int nMode, int nMenuIndex, int nCurrentPageId, HttpServletRequest request )
  167.     {
  168.         XmlUtil.beginElement( strXml, XmlContent.TAG_MENU );
  169.         XmlUtil.addElement( strXml, XmlContent.TAG_MENU_INDEX, nMenuIndex );
  170.         XmlUtil.addElement( strXml, XmlContent.TAG_PAGE_ID, menuPage.getId( ) );
  171.         XmlUtil.addElementHtml( strXml, XmlContent.TAG_PAGE_NAME, menuPage.getName( ) );
  172.         XmlUtil.addElementHtml( strXml, XmlContent.TAG_CURRENT_PAGE_ID, String.valueOf( nCurrentPageId ) );

  173.         Collection<Page> listSubLevelMenuPages = PageHome.getChildPagesMinimalData( menuPage.getId( ) );

  174.         // add element submenu-list only if list not empty
  175.         if ( !listSubLevelMenuPages.isEmpty( ) )
  176.         {
  177.             // Seek of the sub-menus
  178.             XmlUtil.beginElement( strXml, XmlContent.TAG_SUBLEVEL_MENU_LIST );

  179.             int nSubLevelMenuIndex = 1;

  180.             for ( Page subLevelMenuPage : listSubLevelMenuPages )
  181.             {
  182.                 if ( ( subLevelMenuPage.isVisible( request ) ) || ( nMode == MODE_ADMIN ) )
  183.                 {
  184.                     XmlUtil.beginElement( strXml, XmlContent.TAG_SUBLEVEL_MENU );
  185.                     XmlUtil.addElement( strXml, XmlContent.TAG_MENU_INDEX, nMenuIndex );
  186.                     XmlUtil.addElement( strXml, XmlContent.TAG_SUBLEVEL_INDEX, nSubLevelMenuIndex );
  187.                     XmlUtil.addElement( strXml, XmlContent.TAG_PAGE_ID, subLevelMenuPage.getId( ) );
  188.                     XmlUtil.addElementHtml( strXml, XmlContent.TAG_PAGE_NAME, subLevelMenuPage.getName( ) );
  189.                     XmlUtil.endElement( strXml, XmlContent.TAG_SUBLEVEL_MENU );
  190.                     XmlUtil.addElementHtml( strXml, XmlContent.TAG_CURRENT_PAGE_ID, String.valueOf( nCurrentPageId ) );
  191.                 }
  192.             }

  193.             XmlUtil.endElement( strXml, XmlContent.TAG_SUBLEVEL_MENU_LIST );
  194.         }

  195.         XmlUtil.endElement( strXml, XmlContent.TAG_MENU );
  196.     }

  197.     private StyleSheet getMenuXslSource( int nMode, int nPart )
  198.     {
  199.         // Use the same stylesheet for normal or admin mode
  200.         StyleSheet xslSource;

  201.         // Selection of the XSL stylesheet
  202.         switch( nMode )
  203.         {
  204.             case MODE_NORMAL:
  205.             case MODE_ADMIN:
  206.                 xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_MAIN_MENU_ID, MODE_NORMAL );

  207.                 break;

  208.             default:
  209.                 xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_MAIN_MENU_ID, nMode );

  210.                 break;
  211.         }

  212.         if ( nPart == MENU_INIT )
  213.         {
  214.             switch( nMode )
  215.             {
  216.                 case MODE_NORMAL:
  217.                 case MODE_ADMIN:
  218.                     xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_MENU_INIT_ID, MODE_NORMAL );

  219.                     break;

  220.                 default:
  221.                     xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_MENU_INIT_ID, nMode );

  222.                     break;
  223.             }
  224.         }
  225.         return xslSource;
  226.     }

  227.     /**
  228.      * Returns the key corresponding to the part according to the selected mode
  229.      *
  230.      * @param nMode
  231.      *            The mode
  232.      * @param nPart
  233.      *            the part
  234.      * @param request
  235.      *            The HTTP request
  236.      * @return The key as a String
  237.      */
  238.     private String getKey( int nMode, int nPart, HttpServletRequest request )
  239.     {
  240.         String strRoles = "-";

  241.         if ( SecurityService.isAuthenticationEnable( ) && request != null )
  242.         {
  243.             LuteceUser user = SecurityService.getInstance( ).getRegisteredUser( request );

  244.             if ( ( user != null ) && ( user.getRoles( ) != null ) )
  245.             {
  246.                 String [ ] roles = user.getRoles( );
  247.                 Arrays.sort( roles );
  248.                 strRoles = StringUtils.join( roles, ',' );
  249.             }
  250.         }

  251.         StringBuilder sbKey = new StringBuilder( );
  252.         sbKey.append( "[menu:" ).append( nPart ).append( "][m:" ).append( nMode ).append( "][roles:" ).append( strRoles ).append( ']' );

  253.         return sbKey.toString( );
  254.     }

  255.     @Override
  256.     public void processPageEvent( PageEvent event )
  257.     {
  258.         // page was added, removed or updated; clear cache
  259.         resetCache( );
  260.     }
  261. }