View Javadoc
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.web.xpages;
35  
36  import fr.paris.lutece.portal.business.XmlContent;
37  import fr.paris.lutece.portal.business.page.Page;
38  import fr.paris.lutece.portal.business.page.PageHome;
39  import fr.paris.lutece.portal.business.portalcomponent.PortalComponentHome;
40  import fr.paris.lutece.portal.business.style.ModeHome;
41  import fr.paris.lutece.portal.business.stylesheet.StyleSheet;
42  import fr.paris.lutece.portal.service.html.XmlTransformerService;
43  import fr.paris.lutece.portal.service.i18n.I18nService;
44  import fr.paris.lutece.portal.service.plugin.Plugin;
45  import fr.paris.lutece.portal.service.portal.PortalService;
46  import fr.paris.lutece.portal.service.security.LuteceUser;
47  import fr.paris.lutece.portal.service.security.SecurityService;
48  import fr.paris.lutece.portal.service.util.AppLogService;
49  import fr.paris.lutece.portal.service.util.AppPathService;
50  import fr.paris.lutece.portal.web.admin.AdminPageJspBean;
51  import fr.paris.lutece.util.xml.XmlUtil;
52  
53  import org.apache.commons.lang3.StringUtils;
54  
55  import java.util.Arrays;
56  import java.util.HashMap;
57  import java.util.HashSet;
58  import java.util.Locale;
59  import java.util.Map;
60  import java.util.Properties;
61  import java.util.Set;
62  
63  import javax.servlet.http.HttpServletRequest;
64  
65  /**
66   * This class provides the map of the pages on the site
67   */
68  public class SiteMapApp implements XPageApplication
69  {
70      /**
71       * Serial version UID
72       */
73      private static final long serialVersionUID = 1799476496018552101L;
74      private static final int PORTAL_COMPONENT_SITE_MAP_ID = 6;
75      private static final int MODE_NORMAL = 0;
76      private static final int MODE_ADMIN = 1;
77      private static final String PARAMETER_SITE_PATH = "site-path";
78      private static final String MARKER_TARGET = "target";
79      private static final String TARGET_TOP = "target='_top'";
80      private static final String PROPERTY_SERVICE_NAME = "portal.site.serviceName.siteMapService";
81      private static final String PROPERTY_PATH_LABEL = "portal.site.site_map.pathLabel";
82      private static final String PROPERTY_PAGE_TITLE = "portal.site.site_map.pageTitle";
83  
84      /**
85       * Creates a new SiteMapPage object
86       */
87      public SiteMapApp( )
88      {
89          // Ctor
90      }
91  
92      /**
93       * Returns the localized service name
94       * 
95       * @param locale
96       *            The locale
97       * @return The localized service name
98       */
99      public String getName( Locale locale )
100     {
101         return I18nService.getLocalizedString( PROPERTY_SERVICE_NAME, locale );
102     }
103 
104     /**
105      * Build or get in the cache the page which contains the site map depending on the mode
106      *
107      * @param request
108      *            The Http request
109      * @param nMode
110      *            The selected mode
111      * @param plugin
112      *            The plugin
113      * @return The content of the site map
114      */
115     @Override
116     public XPage getPage( HttpServletRequest request, int nMode, Plugin plugin )
117     {
118         XPagetal/web/xpages/XPage.html#XPage">XPage page = new XPage( );
119         String strKey = getKey( nMode, request );
120 
121         Locale locale = request.getLocale( );
122 
123         SiteMapCacheService siteMapCacheService = SiteMapCacheService.getInstance( );
124 
125         // Check the key in the cache
126         String strCachedPage = siteMapCacheService.isCacheEnable( ) ? (String) siteMapCacheService.getFromCache( strKey ) : null;
127 
128         if ( strCachedPage == null )
129         {
130             // Build the HTML document
131             String strPage = buildPageContent( nMode, request );
132 
133             // Add it to the cache
134             if ( siteMapCacheService.isCacheEnable( ) )
135             {
136                 synchronized( strKey )
137                 {
138                     siteMapCacheService.putInCache( strKey, strPage );
139                 }
140             }
141 
142             page.setPathLabel( I18nService.getLocalizedString( PROPERTY_PATH_LABEL, locale ) );
143             page.setTitle( I18nService.getLocalizedString( PROPERTY_PAGE_TITLE, locale ) );
144             page.setContent( strPage );
145 
146             return page;
147         }
148 
149         // The document exist in the cache
150         page.setPathLabel( I18nService.getLocalizedString( PROPERTY_PATH_LABEL, locale ) );
151         page.setTitle( I18nService.getLocalizedString( PROPERTY_PAGE_TITLE, locale ) );
152         page.setContent( strCachedPage );
153 
154         return page;
155     }
156 
157     /**
158      * Gets the cache key
159      * 
160      * @param nMode
161      *            The mode
162      * @param request
163      *            The HTTP request
164      * @return The key
165      */
166     private String getKey( int nMode, HttpServletRequest request )
167     {
168         String strRoles = "-";
169 
170         if ( SecurityService.isAuthenticationEnable( ) )
171         {
172             LuteceUser user = SecurityService.getInstance( ).getRegisteredUser( request );
173 
174             if ( ( user != null ) && ( user.getRoles( ) != null ) )
175             {
176                 String [ ] roles = user.getRoles( );
177                 Arrays.sort( roles );
178                 strRoles = StringUtils.join( roles, ',' );
179             }
180         }
181 
182         return "[m:" + nMode + "][roles:" + strRoles + "]";
183     }
184 
185     /**
186      * Build an XML document containing the arborescence of the site pages and transform it with the stylesheet combined with the mode
187      * 
188      * @param nMode
189      *            The selected mode
190      * @param request
191      *            The HttpServletRequest
192      * @return The content of the site map
193      */
194     private String buildPageContent( int nMode, HttpServletRequest request )
195     {
196         StringBuffer strArborescenceXml = new StringBuffer( );
197         strArborescenceXml.append( XmlUtil.getXmlHeader( ) );
198 
199         int nLevel = 0;
200         findPages( strArborescenceXml, PortalService.getRootPageId( ), nLevel, new HashSet<>( ), request );
201 
202         // Added in v1.3
203         // Use the same stylesheet for normal or admin mode
204         StyleSheet xslSource;
205 
206         switch( nMode )
207         {
208             case MODE_NORMAL:
209             case MODE_ADMIN:
210                 xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_SITE_MAP_ID, MODE_NORMAL );
211 
212                 break;
213 
214             default:
215                 xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_SITE_MAP_ID, nMode );
216 
217                 break;
218         }
219 
220         // Added in v1.3
221         // Add a path param for choose url to use in admin or normal mode
222         Map<String, String> mapParamRequest = new HashMap<>( );
223 
224         if ( nMode != MODE_ADMIN )
225         {
226             mapParamRequest.put( PARAMETER_SITE_PATH, AppPathService.getPortalUrl( ) );
227         }
228         else
229         {
230             mapParamRequest.put( PARAMETER_SITE_PATH, AppPathService.getAdminPortalUrl( ) );
231             mapParamRequest.put( MARKER_TARGET, TARGET_TOP );
232         }
233 
234         Properties outputProperties = ModeHome.getOuputXslProperties( nMode );
235 
236         XmlTransformerServicervice.html#XmlTransformerService">XmlTransformerService xmlTransformerService = new XmlTransformerService( );
237 
238         return xmlTransformerService.transformBySourceWithXslCache( strArborescenceXml.toString( ), xslSource, mapParamRequest, outputProperties );
239     }
240 
241     /**
242      * Build recursively the XML document containing the arborescence of the site pages
243      * 
244      * @param strXmlArborescence
245      *            The buffer in which adding the current page of the arborescence
246      * @param nPageId
247      *            The current page of the recursive course
248      * @param nLevel
249      *            The depth level of the page in the arborescence
250      * @param request
251      *            The HttpServletRequest
252      */
253     private void findPages( StringBuffer strXmlArborescence, int nPageId, int nLevel, Set<Integer> seenPages, HttpServletRequest request )
254     {
255         if ( !seenPages.add( nPageId ) )
256         {
257             AppLogService.error( "SiteMapApp : A cycle exists in pages; page id {} was already processed", nPageId );
258             return;
259         }
260         Page page = PageHome.getPage( nPageId );
261 
262         if ( page.isVisible( request ) )
263         {
264             XmlUtil.beginElement( strXmlArborescence, XmlContent.TAG_PAGE );
265             XmlUtil.addElement( strXmlArborescence, XmlContent.TAG_PAGE_ID, page.getId( ) );
266             XmlUtil.addElementHtml( strXmlArborescence, XmlContent.TAG_PAGE_NAME, page.getName( ) );
267             XmlUtil.addElement( strXmlArborescence, XmlContent.TAG_PAGE_DESCRIPTION, page.getDescription( ) );
268             XmlUtil.addElement( strXmlArborescence, XmlContent.TAG_PAGE_LEVEL, nLevel );
269 
270             AdminPageJspBeanminPageJspBean.html#AdminPageJspBean">AdminPageJspBean adminPage = new AdminPageJspBean( );
271 
272             if ( page.getImageContent( ) != null )
273             {
274                 int nImageLength = page.getImageContent( ).length;
275 
276                 if ( nImageLength >= 1 )
277                 {
278                     String strPageId = Integer.toString( page.getId( ) );
279                     XmlUtil.addElement( strXmlArborescence, XmlContent.TAG_PAGE_IMAGE, adminPage.getResourceImagePage( page, strPageId ) );
280                 }
281             }
282 
283             XmlUtil.beginElement( strXmlArborescence, XmlContent.TAG_CHILD_PAGES_LIST );
284 
285             for ( Page pageChild : PageHome.getChildPagesMinimalData( nPageId ) )
286             {
287                 findPages( strXmlArborescence, pageChild.getId( ), nLevel + 1, seenPages, request );
288             }
289 
290             XmlUtil.endElement( strXmlArborescence, XmlContent.TAG_CHILD_PAGES_LIST );
291             XmlUtil.endElement( strXmlArborescence, XmlContent.TAG_PAGE );
292         }
293     }
294 }