View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de 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.page;
35  
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.page.PageRoleRemovalListener;
39  import fr.paris.lutece.portal.business.portlet.Portlet;
40  import fr.paris.lutece.portal.business.portlet.PortletRoleRemovalListener;
41  import fr.paris.lutece.portal.business.portlet.PortletType;
42  import fr.paris.lutece.portal.business.style.ModeHome;
43  import fr.paris.lutece.portal.business.user.AdminUser;
44  import fr.paris.lutece.portal.service.admin.AdminUserService;
45  import fr.paris.lutece.portal.service.cache.ICacheKeyService;
46  import fr.paris.lutece.portal.service.content.PageData;
47  import fr.paris.lutece.portal.service.html.XmlTransformerService;
48  import fr.paris.lutece.portal.service.i18n.I18nService;
49  import fr.paris.lutece.portal.service.image.ImageResource;
50  import fr.paris.lutece.portal.service.image.ImageResourceManager;
51  import fr.paris.lutece.portal.service.image.ImageResourceProvider;
52  import fr.paris.lutece.portal.service.includes.PageInclude;
53  import fr.paris.lutece.portal.service.includes.PageIncludeService;
54  import fr.paris.lutece.portal.service.message.SiteMessageException;
55  import fr.paris.lutece.portal.service.portal.PortalService;
56  import fr.paris.lutece.portal.service.portal.ThemesService;
57  import fr.paris.lutece.portal.service.portlet.PortletEvent;
58  import fr.paris.lutece.portal.service.portlet.PortletEventListener;
59  import fr.paris.lutece.portal.service.portlet.PortletResourceIdService;
60  import fr.paris.lutece.portal.service.rbac.RBACService;
61  import fr.paris.lutece.portal.service.security.LuteceUser;
62  import fr.paris.lutece.portal.service.security.SecurityService;
63  import fr.paris.lutece.portal.service.template.AppTemplateService;
64  import fr.paris.lutece.portal.service.util.AppLogService;
65  import fr.paris.lutece.portal.service.util.AppPathService;
66  import fr.paris.lutece.portal.service.util.AppPropertiesService;
67  import fr.paris.lutece.portal.service.util.RemovalListenerService;
68  import fr.paris.lutece.portal.web.LocalVariables;
69  import fr.paris.lutece.portal.web.constants.Parameters;
70  import fr.paris.lutece.portal.web.l10n.LocaleService;
71  import fr.paris.lutece.util.html.HtmlTemplate;
72  import fr.paris.lutece.util.url.UrlItem;
73  
74  import org.apache.commons.lang.StringUtils;
75  
76  import java.io.IOException;
77  
78  import java.util.ArrayList;
79  import java.util.Collection;
80  import java.util.Enumeration;
81  import java.util.HashMap;
82  import java.util.List;
83  import java.util.Locale;
84  import java.util.Map;
85  import java.util.Map.Entry;
86  import java.util.Properties;
87  
88  import javax.inject.Inject;
89  
90  import javax.servlet.http.HttpServletRequest;
91  
92  
93  /**
94   * This class delivers pages to web componants. It handles XML tranformation to
95   * HTML and provides a cache feature in order to reduce the number of
96   * tranformations.
97   */
98  public class PageService implements IPageService, ImageResourceProvider, PageEventListener, PortletEventListener
99  {
100     // //////////////////////////////////////////////////////////////////////////
101     // Variables
102 
103     /**
104      * Key for redirections
105      */
106     public static final String REDIRECTION_KEY = "redirect:";
107 
108     // Templates
109     /** Access denied template */
110     public static final String TEMPLATE_PAGE_ACCESS_DENIED = "/skin/site/page_access_denied.html";
111 
112     /** Access Controled template */
113     public static final String TEMPLATE_PAGE_ACCESS_CONTROLED = "/skin/site/page_access_controled.html";
114     private static final String TEMPLATE_ADMIN_BUTTONS = "/admin/admin_buttons.html";
115     private static final String TEMPLATE_COLUMN_OUTLINE = "/admin/column_outline.html";
116 
117     // Markers
118     private static final String MARK_PORTLET = "portlet";
119     private static final String MARK_STATUS_PUBLISHED = "portlet_status_published";
120     private static final String MARK_STATUS_UNPUBLISHED = "portlet_status_unpublished";
121     private static final String MARK_CUSTOM_ACTIONS = "custom_action_list";
122     private static final String MARK_URL_LOGIN = "url_login";
123     private static final String MARKER_TARGET = "target";
124     private static final String MARKER_IS_USER_AUTHENTICATED = "is-user-authenticated";
125     private static final String MARK_COLUMN_CONTENT = "column_content";
126     private static final String MARK_COLUMN_ID = "column_id";
127 
128     // Parameters
129     private static final String PARAMETER_SITE_PATH = "site-path";
130     private static final String PARAMETER_USER_SELECTED_LOCALE = "user-selected-language";
131     private static final String PARAMETER_PLUGIN_NAME = "plugin-name";
132     private static final String PARAMETER_PORTLET = "portlet";
133 
134     // Properties
135     private static final String PROPERTY_MESSAGE_PAGE_ACCESS_DENIED = "portal.site.message.pageAccessDenied";
136     private static final String CONTENT_SERVICE_NAME = "PageService";
137     private static final String PROPERTY_COLUMN_MAX = "nb.columns";
138     private static final int DEFAULT_COLUMN_MAX = 5;
139     private static final String KEY_THEME = "theme";
140     private static final String TARGET_TOP = "target='_top'";
141     private static final String WELCOME_PAGE_ID = "1";
142     private static final String WELCOME_PAGE_CACHE_KEY = "mode0";
143     private static final int MODE_ADMIN = 1;
144     private static final String VALUE_TRUE = "1";
145     private static final String VALUE_FALSE = "0";
146     private static final String XSL_UNIQUE_PREFIX = "page-";
147     private static final String ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED = "core.canPageBeCached";
148 
149     // Specific for plugin-document
150     private static final String DOCUMENT_LIST_PORTLET = "DOCUMENT_LIST_PORTLET";
151     private static final String DOCUMENT_PORTLET = "DOCUMENT_PORTLET";
152     private static final String DOCUMENT_ACTION_URL = "jsp/admin/plugins/document/ManagePublishing.jsp";
153     private static final String DOCUMENT_IMAGE_URL = "images/admin/skin/actions/publish.png";
154     private static final String DOCUMENT_TITLE = "portal.site.portletPreview.buttonManage";
155     private static final int MAX_COLUMNS = AppPropertiesService.getPropertyInt( PROPERTY_COLUMN_MAX, DEFAULT_COLUMN_MAX );
156     private static List<PageEventListener> _listEventListeners = new ArrayList<PageEventListener>(  );
157     private ICacheKeyService _cksPage;
158     private ICacheKeyService _cksPortlet;
159     private PageCacheService _cachePages;
160     private PortletCacheService _cachePortlets;
161 
162     /**
163      * Creates a new PageService object.
164      * @deprecated use
165      *             {@link #PageService(PageCacheService, PortletCacheService)}
166      *             instead.
167      */
168     @Deprecated
169     public PageService(  )
170     {
171         init(  );
172     }
173 
174     /**
175      * Creates a new PageService object.
176      * @param pageCacheService the page cache service
177      * @param portletCacheService the portlet cache service
178      */
179     @Inject
180     public PageService( PageCacheService pageCacheService, PortletCacheService portletCacheService )
181     {
182         _cachePages = pageCacheService;
183         _cachePortlets = portletCacheService;
184         init(  );
185     }
186 
187     /**
188      * Initializes the service
189      */
190     private void init(  )
191     {
192         _cachePages.initCache(  );
193         _cachePortlets.initCache(  );
194         ImageResourceManager.registerProvider( this );
195         addPageEventListener( this );
196     }
197 
198     /**
199      * Returns the Content Service name
200      *
201      * @return The name as a String
202      */
203     public String getName(  )
204     {
205         return CONTENT_SERVICE_NAME;
206     }
207 
208     /**
209      * Returns the page for a given ID. The page is built using XML data of each
210      * portlet or retrieved from the cache if it's enable.
211      *
212      * @param request
213      *            The page ID
214      * @param nMode
215      *            The current mode.
216      * @return The HTML code of the page as a String.
217      * @throws SiteMessageException
218      *             If a message shouldbe displayed
219      */
220     @Override
221     public String getPage( HttpServletRequest request, int nMode )
222         throws SiteMessageException
223     {
224         String strPageId = request.getParameter( Parameters.PAGE_ID );
225 
226         return getPage( strPageId, nMode, request );
227     }
228 
229     /**
230      * Returns the page for a given ID. The page is built using XML data of each
231      * portlet or retrieved from the cache if it's enable.
232      *
233      * @param strIdPage
234      *            The page ID
235      * @param nMode
236      *            The current mode.
237      * @param request
238      *            The HttpRequest
239      * @return The HTML code of the page as a String.
240      * @throws SiteMessageException
241      *             occurs when a site message need to be displayed
242      */
243     @Override
244     public String getPage( String strIdPage, int nMode, HttpServletRequest request )
245         throws SiteMessageException
246     {
247         try
248         {
249             String strPage = "";
250 
251             // The cache is enable !
252             if ( _cachePages.isCacheEnable(  ) )
253             {
254                 // Get request paramaters and store them in a HashMap
255                 Enumeration<?> enumParam = request.getParameterNames(  );
256                 HashMap<String, String> htParamRequest = new HashMap<String, String>(  );
257                 String paramName = "";
258 
259                 while ( enumParam.hasMoreElements(  ) )
260                 {
261                     paramName = (String) enumParam.nextElement(  );
262                     htParamRequest.put( paramName, request.getParameter( paramName ) );
263                 }
264 
265                 if ( !htParamRequest.containsKey( Parameters.PAGE_ID ) )
266                 {
267                     htParamRequest.put( Parameters.PAGE_ID, strIdPage );
268                 }
269 
270                 if ( !htParamRequest.containsKey( Parameters.BASE_URL ) )
271                 {
272                     htParamRequest.put( Parameters.BASE_URL, AppPathService.getBaseUrl( request ) );
273                 }
274 
275                 LuteceUser user = SecurityService.getInstance(  ).getRegisteredUser( request );
276                 String strUserTheme = ThemesService.getUserTheme( request );
277 
278                 if ( strUserTheme != null )
279                 {
280                     htParamRequest.put( KEY_THEME, strUserTheme );
281                 }
282 
283                 // we add the key in the memory key only if cache is enable
284                 String strKey = getKey( htParamRequest, nMode, user );
285 
286                 // get page from cache
287                 strPage = (String) _cachePages.getFromCache( strKey );
288 
289                 if ( strPage == null )
290                 {
291                     // only one thread can evaluate the page
292                     synchronized ( strKey )
293                     {
294                         // can be useful if an other thread had evaluate the
295                         // page
296                         strPage = (String) _cachePages.getFromCache( strKey );
297 
298                         // ignore checkstyle, this double verification is useful
299                         // when page cache has been created when thread is
300                         // blocked on synchronized
301                         if ( strPage == null )
302                         {
303                             Boolean bCanBeCached = Boolean.TRUE;
304 
305                             AppLogService.debug( "Page generation " + strKey );
306 
307                             RedirectionResponseWrapper response = new RedirectionResponseWrapper( LocalVariables.getResponse(  ) );
308 
309                             LocalVariables.setLocal( LocalVariables.getConfig(  ), LocalVariables.getRequest(  ),
310                                 response );
311                             request.setAttribute( ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED, null );
312                             // The key is not in the cache, so we have to build
313                             // the page
314                             strPage = buildPageContent( strIdPage, nMode, request, bCanBeCached );
315 
316                             // We check if the page contains portlets that can not be cached. 
317                             if ( ( request.getAttribute( ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED ) != null ) &&
318                                     !(Boolean) request.getAttribute( ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED ) )
319                             {
320                                 bCanBeCached = Boolean.FALSE;
321                             }
322 
323                             if ( response.getRedirectLocation(  ) != null )
324                             {
325                                 AppLogService.debug( "Redirection found " + response.getRedirectLocation(  ) );
326                                 strPage = REDIRECTION_KEY + response.getRedirectLocation(  );
327                             }
328 
329                             // Add the page to the cache if the page can be
330                             // cached
331                             if ( bCanBeCached.booleanValue(  ) && ( nMode != MODE_ADMIN ) )
332                             {
333                                 _cachePages.putInCache( strKey, strPage );
334                             }
335                         }
336                         else
337                         {
338                             AppLogService.debug( "Page read from cache after synchronisation " + strKey );
339                         }
340                     }
341                 }
342                 else
343                 {
344                     AppLogService.debug( "Page read from cache " + strKey );
345                 }
346 
347                 // redirection handling
348                 if ( strPage.startsWith( REDIRECTION_KEY ) )
349                 {
350                     strPage = strPage.replaceFirst( REDIRECTION_KEY, "" );
351 
352                     try
353                     {
354                         LocalVariables.getResponse(  ).sendRedirect( strPage );
355                     }
356                     catch ( IOException e )
357                     {
358                         AppLogService.error( "Error on sendRedirect for " + strPage );
359                     }
360                 }
361             }
362             else
363             {
364                 Boolean bCanBeCached = Boolean.FALSE;
365                 strPage = buildPageContent( strIdPage, nMode, request, bCanBeCached );
366             }
367 
368             return strPage;
369         }
370         catch ( NumberFormatException nfe )
371         {
372             AppLogService.error( "PageService.getPage() : " + nfe.getLocalizedMessage(  ), nfe );
373 
374             throw new PageNotFoundException(  );
375         }
376     }
377 
378     /**
379      * Build the page content.
380      *
381      * @param strIdPage
382      *            The page ID
383      * @param nMode
384      *            The current mode.
385      * @param request
386      *            The HttpRequest
387      * @param bCanBeCached
388      *            The boolean
389      * @return The HTML code of the page as a String.
390      * @throws SiteMessageException
391      *             occurs when a site message need to be displayed
392      */
393     public String buildPageContent( String strIdPage, int nMode, HttpServletRequest request, Boolean bCanBeCached )
394         throws SiteMessageException
395     {
396         int nIdPage = 0;
397         Page page = null;
398 
399         nIdPage = Integer.parseInt( strIdPage );
400 
401         boolean bPageExist = PageHome.checkPageExist( nIdPage );
402 
403         if ( bPageExist )
404         {
405             page = PageHome.getPage( nIdPage );
406         }
407         else
408         {
409             // If there is a problem finding the page, returns the home page
410             nIdPage = PortalService.getRootPageId(  );
411             page = PageHome.getPage( nIdPage );
412         }
413 
414         PageData data = new PageData(  );
415         data.setName( page.getName(  ) );
416         data.setPagePath( PortalService.getPagePathContent( nIdPage, nMode, request ) );
417         data.setTheme( page.getCodeTheme(  ) );
418         data.setMetaKeywords( page.getMetaKeywords(  ) );
419         data.setMetaDescription( page.getMetaDescription(  ) );
420 
421         // Checks the page role (v1.1)
422         String strRole = page.getRole(  );
423 
424         if ( !strRole.equals( Page.ROLE_NONE ) && ( SecurityService.isAuthenticationEnable(  ) ) &&
425                 ( nMode != MODE_ADMIN ) )
426         {
427             LuteceUser user = SecurityService.getInstance(  ).getRegisteredUser( request );
428 
429             if ( ( user == null ) && ( !SecurityService.getInstance(  ).isExternalAuthentication(  ) ) )
430             {
431                 // The user is not registered and identify itself with the
432                 // Portal authentication
433                 String strAccessControledTemplate = SecurityService.getInstance(  ).getAccessControledTemplate(  );
434                 HashMap<String, Object> model = new HashMap<String, Object>(  );
435                 String strLoginUrl = SecurityService.getInstance(  ).getLoginPageUrl(  );
436                 model.put( MARK_URL_LOGIN, strLoginUrl );
437 
438                 HtmlTemplate tAccessControled = AppTemplateService.getTemplate( strAccessControledTemplate,
439                         request.getLocale(  ), model );
440 
441                 data.setContent( tAccessControled.getHtml(  ) );
442 
443                 return PortalService.buildPageContent( nIdPage, data, nMode, request );
444             }
445 
446             if ( !SecurityService.getInstance(  ).isUserInRole( request, strRole ) )
447             {
448                 // The user doesn't have the correct role
449                 String strAccessDeniedTemplate = SecurityService.getInstance(  ).getAccessDeniedTemplate(  );
450                 HtmlTemplate tAccessDenied = AppTemplateService.getTemplate( strAccessDeniedTemplate,
451                         request.getLocale(  ) );
452                 data.setContent( tAccessDenied.getHtml(  ) );
453 
454                 return PortalService.buildPageContent( nIdPage, data, nMode, request );
455             }
456         }
457 
458         // Added in v2.0
459         // Add the page authorization
460         if ( nMode == MODE_ADMIN )
461         {
462             AdminUser user = AdminUserService.getAdminUser( request );
463 
464             if ( isAuthorizedAdminPage( nIdPage, PageResourceIdService.PERMISSION_VIEW, user ) )
465             {
466                 // Fill a PageData structure for those elements
467                 data.setContent( getPageContent( nIdPage, nMode, request ) );
468             }
469             else
470             {
471                 data.setContent( I18nService.getLocalizedString( PROPERTY_MESSAGE_PAGE_ACCESS_DENIED, user.getLocale(  ) ) );
472             }
473         }
474         else
475         {
476             data.setContent( getPageContent( nIdPage, nMode, request ) );
477         }
478 
479         if ( nIdPage == PortalService.getRootPageId(  ) )
480         {
481             // This page is the home page.
482             data.setHomePage( true );
483         }
484 
485         return PortalService.buildPageContent( nIdPage, data, nMode, request );
486     }
487 
488     /**
489      * Build the page content.
490      *
491      * @param nIdPage
492      *            The page ID
493      * @param nMode
494      *            The current mode.
495      * @param request
496      *            The HttpRequest
497      * @return The HTML code of the page as a String.
498      * @throws SiteMessageException
499      *             occurs when a site message need to be displayed
500      */
501     @Override
502     public String getPageContent( int nIdPage, int nMode, HttpServletRequest request )
503         throws SiteMessageException
504     {
505         Locale locale = ( request == null ) ? LocaleService.getDefault(  ) : request.getLocale(  );
506 
507         String[] arrayContent = new String[MAX_COLUMNS];
508 
509         for ( int i = 0; i < MAX_COLUMNS; i++ )
510         {
511             arrayContent[i] = "";
512         }
513 
514         Page page = PageHome.findByPrimaryKey( nIdPage );
515         Map<String, String> mapParams = getParams( request, nMode, nIdPage );
516         boolean bCanPageBeCached = Boolean.TRUE;
517         LuteceUser user = SecurityService.getInstance(  ).getRegisteredUser( request );
518 
519         for ( Portlet portlet : page.getPortlets(  ) )
520         {
521             int nCol = portlet.getColumn(  ) - 1;
522 
523             if ( nCol < MAX_COLUMNS )
524             {
525                 arrayContent[nCol] += getPortletContent( request, portlet, mapParams, nMode );
526             }
527 
528             // We check if the portlet can be cached
529             if ( ( user != null ) ? ( !portlet.canBeCachedForConnectedUsers(  ) )
530                                       : ( !portlet.canBeCachedForAnonymousUsers(  ) ) )
531             {
532                 bCanPageBeCached = false;
533             }
534         }
535 
536         // Add columns outline in admin mode
537         if ( nMode == MODE_ADMIN )
538         {
539             for ( int i = 0; i < MAX_COLUMNS; i++ )
540             {
541                 arrayContent[i] = addColumnOutline( i + 1, arrayContent[i], locale );
542             }
543         }
544 
545         // We save that the page that is generating can not be cached
546         if ( !bCanPageBeCached )
547         {
548             request.setAttribute( ATTRIBUTE_CORE_CAN_PAGE_BE_CACHED, false );
549         }
550 
551         Map<String, Object> rootModel = new HashMap<String, Object>(  );
552 
553         for ( int j = 0; j < MAX_COLUMNS; j++ )
554         {
555             rootModel.put( "page_content_col" + ( j + 1 ), arrayContent[j] );
556         }
557 
558         List<PageInclude> listIncludes = PageIncludeService.getIncludes(  );
559         PageData data = new PageData(  );
560 
561         for ( PageInclude pic : listIncludes )
562         {
563             pic.fillTemplate( rootModel, data, nMode, request );
564         }
565 
566         HtmlTemplate t = AppTemplateService.getTemplate( page.getTemplate(  ), locale, rootModel );
567 
568         return t.getHtml(  );
569     }
570 
571     /**
572      * Add the HTML code to display column outlines
573      *
574      * @param columnId
575      *            the column id
576      * @param content
577      *            the column content
578      * @param locale
579      *            the locale
580      * @return The column code
581      */
582     private String addColumnOutline( int columnId, String content, Locale locale )
583     {
584         Map<String, Object> model = new HashMap<String, Object>( 2 );
585         model.put( MARK_COLUMN_CONTENT, content );
586         model.put( MARK_COLUMN_ID, columnId );
587 
588         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_COLUMN_OUTLINE, locale, model );
589 
590         return template.getHtml(  );
591     }
592 
593     /**
594      * Get the portlet content
595      *
596      * @param request
597      *            The HTTP request
598      * @param portlet
599      *            The portlet
600      * @param mapRequestParams
601      *            request parameters
602      * @param nMode
603      *            The mode
604      * @return The content
605      * @throws SiteMessageException
606      *             If an error occurs
607      */
608     private String getPortletContent( HttpServletRequest request, Portlet portlet,
609         Map<String, String> mapRequestParams, int nMode )
610         throws SiteMessageException
611     {
612         if ( ( nMode != MODE_ADMIN ) && ( portlet.getStatus(  ) == Portlet.STATUS_UNPUBLISHED ) )
613         {
614             return StringUtils.EMPTY;
615         }
616 
617         String strRole = portlet.getRole(  );
618 
619         if ( !strRole.equals( Page.ROLE_NONE ) && ( SecurityService.isAuthenticationEnable(  ) ) &&
620                 ( nMode != MODE_ADMIN ) )
621         {
622             if ( !SecurityService.getInstance(  ).isUserInRole( request, strRole ) )
623             {
624                 return StringUtils.EMPTY;
625             }
626         }
627 
628         if ( request != null )
629         {
630             String strPluginName = portlet.getPluginName(  );
631             request.setAttribute( PARAMETER_PLUGIN_NAME, strPluginName );
632         }
633 
634         String strPortletContent = StringUtils.EMPTY;
635 
636         // Add the admin buttons for portlet management on admin mode
637         if ( nMode == MODE_ADMIN )
638         {
639             strPortletContent = addAdminButtons( request, portlet );
640         }
641 
642         String strKey = StringUtils.EMPTY;
643 
644         if ( portlet.isContentGeneratedByXmlAndXsl(  ) )
645         {
646             Map<String, String> mapParams = mapRequestParams;
647             Map<String, String> mapXslParams = portlet.getXslParams(  );
648 
649             if ( mapParams != null )
650             {
651                 if ( mapXslParams != null )
652                 {
653                     for ( Entry<String, String> entry : mapXslParams.entrySet(  ) )
654                     {
655                         mapParams.put( entry.getKey(  ), entry.getValue(  ) );
656                     }
657                 }
658             }
659             else
660             {
661                 mapParams = mapXslParams;
662             }
663 
664             Properties outputProperties = ModeHome.getOuputXslProperties( nMode );
665 
666             String strXslUniqueId = XSL_UNIQUE_PREFIX + String.valueOf( portlet.getStyleId(  ) );
667 
668             if ( ( ( nMode != MODE_ADMIN ) && _cachePortlets.isCacheEnable(  ) ) )
669             {
670                 LuteceUser user = null;
671 
672                 if ( SecurityService.isAuthenticationEnable(  ) )
673                 {
674                     user = SecurityService.getInstance(  ).getRegisteredUser( request );
675                 }
676 
677                 boolean bCanBeCached = ( user != null ) ? ( portlet.canBeCachedForConnectedUsers(  ) )
678                                                         : ( portlet.canBeCachedForAnonymousUsers(  ) );
679 
680                 if ( bCanBeCached )
681                 {
682                     mapParams.put( PARAMETER_PORTLET, String.valueOf( portlet.getId(  ) ) );
683                     strKey = _cksPortlet.getKey( mapParams, nMode, user );
684 
685                     String strPortlet = (String) _cachePortlets.getFromCache( strKey );
686 
687                     if ( strPortlet != null )
688                     {
689                         return strPortlet;
690                     }
691                 }
692             }
693 
694             XmlTransformerService xmlTransformerService = new XmlTransformerService(  );
695             String strPortletXmlContent = portlet.getXml( request );
696             strPortletContent += xmlTransformerService.transformBySourceWithXslCache( strPortletXmlContent,
697                 portlet.getXslSource( nMode ), strXslUniqueId, mapParams, outputProperties );
698         }
699         else
700         {
701             if ( ( ( nMode != MODE_ADMIN ) && _cachePortlets.isCacheEnable(  ) ) )
702             {
703                 LuteceUser user = null;
704 
705                 if ( SecurityService.isAuthenticationEnable(  ) )
706                 {
707                     user = SecurityService.getInstance(  ).getRegisteredUser( request );
708                 }
709 
710                 boolean bCanBeCached = ( user != null ) ? ( portlet.canBeCachedForConnectedUsers(  ) )
711                                                         : ( portlet.canBeCachedForAnonymousUsers(  ) );
712 
713                 if ( bCanBeCached )
714                 {
715                     mapRequestParams.put( PARAMETER_PORTLET, String.valueOf( portlet.getId(  ) ) );
716                     strKey = _cksPortlet.getKey( mapRequestParams, nMode, user );
717 
718                     String strPortlet = (String) _cachePortlets.getFromCache( strKey );
719 
720                     if ( strPortlet != null )
721                     {
722                         return strPortlet;
723                     }
724                 }
725             }
726 
727             strPortletContent += portlet.getHtmlContent( request );
728         }
729 
730         if ( ( nMode != MODE_ADMIN ) && _cachePortlets.isCacheEnable(  ) && StringUtils.isNotEmpty( strKey ) )
731         {
732             _cachePortlets.putInCache( strKey, strPortletContent );
733         }
734 
735         return strPortletContent;
736     }
737 
738     /**
739      * Build the Cache HashMap key for pages Goal is to be able to have a
740      * synchronized on the key but a synchronize only work with strict
741      * reference. So we manage an hashmap of string reference for cache keys to
742      * be able to get them back.
743      *
744      * @param mapParams
745      *            The Map params
746      * @param nMode
747      *            The current mode.
748      * @param user
749      *            Current Lutece user
750      * @return The HashMap key for articles pages as a String.
751      */
752     private String getKey( Map<String, String> mapParams, int nMode, LuteceUser user )
753     {
754         String strKey = _cksPage.getKey( mapParams, nMode, user );
755 
756         return _cachePages.getKey( strKey );
757     }
758 
759     /**
760      * Remove a page from the cache
761      *
762      * @param nIdPage
763      *            The page ID
764      */
765     private void invalidatePage( int nIdPage )
766     {
767         String strIdPage = String.valueOf( nIdPage );
768         invalidatePage( strIdPage );
769     }
770 
771     /**
772      * @param cacheKeyService
773      *            the _cacheKeyService to set
774      */
775     public void setPageCacheKeyService( ICacheKeyService cacheKeyService )
776     {
777         _cksPage = cacheKeyService;
778     }
779 
780     /**
781      * @param cacheKeyService
782      *            the _cacheKeyService to set
783      */
784     public void setPortletCacheKeyService( ICacheKeyService cacheKeyService )
785     {
786         _cksPortlet = cacheKeyService;
787     }
788 
789     /**
790      * @param removalService
791      *            the removal listener service
792      */
793     public void setRoleRemovalService( RemovalListenerService removalService )
794     {
795         removalService.registerListener( new PageRoleRemovalListener(  ) );
796         removalService.registerListener( new PortletRoleRemovalListener(  ) );
797     }
798 
799     /**
800      * Remove a page from the cache
801      *
802      * @param strIdPage
803      *            The page ID
804      */
805     private void invalidatePage( String strIdPage )
806     {
807         if ( _cachePages.isCacheEnable(  ) )
808         {
809             String strKey = "[" + Parameters.PAGE_ID + ":" + strIdPage + "]";
810 
811             for ( String strKeyTemp : (List<String>) _cachePages.getCache(  ).getKeys(  ) )
812             {
813                 if ( ( strKeyTemp.indexOf( strKey ) != -1 ) ||
814                         ( WELCOME_PAGE_ID.equals( strIdPage ) && WELCOME_PAGE_CACHE_KEY.equals( strKeyTemp ) ) )
815                 {
816                     _cachePages.getCache(  ).remove( strKeyTemp );
817 
818                     if ( AppLogService.isDebugEnabled(  ) )
819                     {
820                         AppLogService.debug( "Page (cache key : " + strKeyTemp + ") removed from the cache." );
821                     }
822                 }
823             }
824         }
825     }
826 
827     // ///////////////////////////////////////////////////////////////////////////
828     // Events Listeners management
829     /**
830      * Add a new page event listener
831      *
832      * @param listener
833      *            An event listener to add
834      */
835     public static void addPageEventListener( PageEventListener listener )
836     {
837         _listEventListeners.add( listener );
838         AppLogService.info( "New Page Event Listener registered : " + listener.getClass(  ).getName(  ) );
839     }
840 
841     /**
842      * Notify an event to all listeners
843      *
844      * @param event
845      *            A page Event
846      */
847     private void notifyListeners( PageEvent event )
848     {
849         for ( PageEventListener listener : _listEventListeners )
850         {
851             listener.processPageEvent( event );
852         }
853     }
854 
855     /**
856      * Returns the resource type Id
857      *
858      * @return The resource type Id
859      */
860     @Override
861     public String getResourceTypeId(  )
862     {
863         return Page.IMAGE_RESOURCE_TYPE_ID;
864     }
865 
866     /**
867      * Gets the image resource for a given resource
868      *
869      * @param nIdResource
870      *            The Resource id
871      * @return The image resource
872      */
873     @Override
874     public ImageResource getImageResource( int nIdResource )
875     {
876         return PageHome.getImageResource( nIdResource );
877     }
878 
879     /**
880      * Create a page
881      *
882      * @param page
883      *            The page to create
884      */
885     @Override
886     public void createPage( Page page )
887     {
888         PageHome.create( page );
889 
890         PageEvent event = new PageEvent( page, PageEvent.PAGE_CREATED );
891         notifyListeners( event );
892     }
893 
894     /**
895      * Update a given page
896      *
897      * @param page
898      *            The page to update
899      */
900     @Override
901     public void updatePage( Page page )
902     {
903         PageHome.update( page );
904 
905         PageEvent event = new PageEvent( page, PageEvent.PAGE_CONTENT_MODIFIED );
906         notifyListeners( event );
907     }
908 
909     /**
910      * Remove a given page
911      *
912      * @param nPageId
913      *            The page Id
914      */
915     @Override
916     public void removePage( int nPageId )
917     {
918         Page page = PageHome.findByPrimaryKey( nPageId );
919         PageEvent event = new PageEvent( page, PageEvent.PAGE_DELETED );
920         PageHome.remove( nPageId );
921         notifyListeners( event );
922     }
923 
924     /**
925      * Process a page event
926      *
927      * @param event
928      *            The event to process
929      */
930     @Override
931     public void processPageEvent( PageEvent event )
932     {
933         Page page = event.getPage(  );
934         invalidatePage( page.getId(  ) );
935 
936         // Clearing ALL cache is not needed anymore
937         // PortalService.resetCache( );
938     }
939 
940     /**
941      * {@inheritDoc}
942      */
943     @Override
944     public void processPortletEvent( PortletEvent event )
945     {
946         invalidateContent( event.getPageId(  ) );
947     }
948 
949     /**
950      * Invalidate Page Content
951      *
952      * @param nPageId
953      *            The Page ID
954      */
955     @Override
956     public void invalidateContent( int nPageId )
957     {
958         Page page = PageHome.findByPrimaryKey( nPageId );
959         PageEvent event = new PageEvent( page, PageEvent.PAGE_CONTENT_MODIFIED );
960         notifyListeners( event );
961     }
962 
963     /**
964      * Check that a given user is allowed to access a page for a given
965      * permission
966      *
967      * @param nIdPage
968      *            the id of the page to check
969      * @param strPermission
970      *            the permission needed
971      * @param user
972      *            The current user
973      * @return true if authorized, otherwise false
974      */
975     @Override
976     public boolean isAuthorizedAdminPage( int nIdPage, String strPermission, AdminUser user )
977     {
978         Page page = PageHome.findByPrimaryKey( nIdPage );
979 
980         if ( page.getIdAuthorizationNode(  ) != null )
981         {
982             String strAuthorizationNode = Integer.toString( page.getIdAuthorizationNode(  ) );
983 
984             return ( RBACService.isAuthorized( Page.RESOURCE_TYPE, strAuthorizationNode, strPermission, user ) );
985         }
986 
987         return true;
988     }
989 
990     /**
991      * Add the HTML code to display admin buttons under each portlet
992      *
993      * @param request
994      *            The Http request
995      * @param portlet
996      *            The portlet
997      * @return The buttons code
998      */
999     private String addAdminButtons( HttpServletRequest request, Portlet portlet )
1000     {
1001         AdminUser user = AdminUserService.getAdminUser( request );
1002 
1003         if ( RBACService.isAuthorized( PortletType.RESOURCE_TYPE, portlet.getPortletTypeId(  ),
1004                     PortletResourceIdService.PERMISSION_MANAGE, user ) )
1005         {
1006             Locale locale = user.getLocale(  );
1007             Collection<PortletCustomAdminAction> listCustomActions = new ArrayList<PortletCustomAdminAction>(  );
1008 
1009             // TODO : listCustomActions should be provided by PortletType
1010             // FIXME : Delete plugin-document specifics
1011             if ( portlet.getPortletTypeId(  ).equals( DOCUMENT_LIST_PORTLET ) ||
1012                     portlet.getPortletTypeId(  ).equals( DOCUMENT_PORTLET ) )
1013             {
1014                 PortletCustomAdminAction customAction = new PortletCustomAdminAction(  );
1015                 customAction.setActionUrl( DOCUMENT_ACTION_URL );
1016                 customAction.setImageUrl( DOCUMENT_IMAGE_URL );
1017                 customAction.setTitle( DOCUMENT_TITLE );
1018                 listCustomActions.add( customAction );
1019             }
1020 
1021             Map<String, Object> model = new HashMap<String, Object>(  );
1022             model.put( MARK_PORTLET, portlet );
1023             model.put( MARK_STATUS_PUBLISHED, Portlet.STATUS_PUBLISHED );
1024             model.put( MARK_STATUS_UNPUBLISHED, Portlet.STATUS_UNPUBLISHED );
1025             model.put( MARK_CUSTOM_ACTIONS, listCustomActions );
1026 
1027             HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_ADMIN_BUTTONS, locale, model );
1028 
1029             return template.getHtml(  );
1030         }
1031 
1032         return "";
1033     }
1034 
1035     /**
1036      * Gets the params map
1037      *
1038      * @param request
1039      *            The HTTP request
1040      * @param nMode
1041      *            The mode
1042      * @param nIdPage
1043      *            The page ID
1044      * @return the map
1045      */
1046     private Map<String, String> getParams( HttpServletRequest request, int nMode, int nIdPage )
1047     {
1048         Map<String, String> mapModifyParam = new HashMap<String, String>(  );
1049         String paramName = "";
1050 
1051         // Get request paramaters and store them in a HashMap
1052         if ( request != null )
1053         {
1054             Enumeration<?> enumParam = request.getParameterNames(  );
1055 
1056             while ( enumParam.hasMoreElements(  ) )
1057             {
1058                 paramName = (String) enumParam.nextElement(  );
1059                 mapModifyParam.put( paramName, request.getParameter( paramName ) );
1060             }
1061 
1062             // Add selected locale
1063             mapModifyParam.put( PARAMETER_USER_SELECTED_LOCALE,
1064                 LocaleService.getUserSelectedLocale( request ).getLanguage(  ) );
1065         }
1066 
1067         // Added in v1.3
1068         // Add a path param for choose url to use in admin or normal mode
1069         if ( nMode != MODE_ADMIN )
1070         {
1071             mapModifyParam.put( PARAMETER_SITE_PATH, AppPathService.getPortalUrl(  ) );
1072 
1073             if ( SecurityService.isAuthenticationEnable(  ) )
1074             {
1075                 mapModifyParam.put( MARKER_IS_USER_AUTHENTICATED,
1076                     ( SecurityService.getInstance(  ).getRegisteredUser( request ) != null ) ? VALUE_TRUE : VALUE_FALSE );
1077             }
1078         }
1079         else
1080         {
1081             mapModifyParam.put( PARAMETER_SITE_PATH, AppPathService.getAdminPortalUrl(  ) );
1082             mapModifyParam.put( MARKER_TARGET, TARGET_TOP );
1083         }
1084 
1085         if ( !mapModifyParam.containsKey( Parameters.PAGE_ID ) )
1086         {
1087             mapModifyParam.put( Parameters.PAGE_ID, Integer.toString( PortalService.getRootPageId(  ) ) );
1088         }
1089 
1090         return mapModifyParam;
1091     }
1092 
1093     /**
1094      * Management of the image associated to the page
1095      *
1096      * @param strPageId
1097      *            The page identifier
1098      * @return The url
1099      */
1100     public String getResourceImagePage( String strPageId )
1101     {
1102         String strResourceType = getResourceTypeId(  );
1103         UrlItem url = new UrlItem( Parameters.IMAGE_SERVLET );
1104         url.addParameter( Parameters.RESOURCE_TYPE, strResourceType );
1105         url.addParameter( Parameters.RESOURCE_ID, strPageId );
1106 
1107         return url.getUrlWithEntity(  );
1108     }
1109 
1110     /**
1111      * Gets the page cache service.
1112      * @return the page cache service
1113      */
1114     public PageCacheService getPageCacheService(  )
1115     {
1116         return _cachePages;
1117     }
1118 
1119     /**
1120      * Sets the cache page service
1121      * @param pageCacheService the page cache service
1122      */
1123     public void setPageCacheService( PageCacheService pageCacheService )
1124     {
1125         _cachePages = pageCacheService;
1126     }
1127 
1128     /**
1129      * Gets the portlet cache service
1130      * @return the porlet cache service
1131      */
1132     public PortletCacheService getPortletCacheService(  )
1133     {
1134         return _cachePortlets;
1135     }
1136 
1137     /**
1138      * Gets the portlet cache service
1139      * @param portletCacheService the portlet cache service
1140      */
1141     public void setPortletCacheService( PortletCacheService portletCacheService )
1142     {
1143         _cachePortlets = portletCacheService;
1144     }
1145 
1146     /**
1147      * update authorization node of children page
1148      * @param nIdParentPage id of the parent page
1149      * @param nIdNewAuthorizationNode the new authorization id
1150      */
1151     public static void updateChildrenAuthorizationNode( int nIdParentPage, Integer nIdNewAuthorizationNode )
1152     {
1153         List<Integer> listPagesChildren = PageHome.getPagesWhichMustChangeAuthorizationNode( nIdParentPage );
1154 
1155         if ( listPagesChildren != null )
1156         {
1157             for ( Integer idPage : listPagesChildren )
1158             {
1159                 PageHome.updateAuthorizationNode( idPage, nIdNewAuthorizationNode );
1160                 updateChildrenAuthorizationNode( idPage, nIdNewAuthorizationNode );
1161             }
1162         }
1163     }
1164 }