View Javadoc
1   /*
2    * Copyright (c) 2002-2015, 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.portal;
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.cache.AbstractCacheableService;
43  import fr.paris.lutece.portal.service.html.XmlTransformerService;
44  import fr.paris.lutece.portal.service.page.PageEvent;
45  import fr.paris.lutece.portal.service.page.PageEventListener;
46  import fr.paris.lutece.portal.service.page.PageService;
47  import fr.paris.lutece.portal.service.security.LuteceUser;
48  import fr.paris.lutece.portal.service.security.SecurityService;
49  import fr.paris.lutece.util.xml.XmlUtil;
50  
51  import org.apache.commons.lang.StringUtils;
52  
53  import java.util.Arrays;
54  import java.util.Collection;
55  import java.util.HashMap;
56  import java.util.Map;
57  import java.util.Properties;
58  
59  import javax.servlet.http.HttpServletRequest;
60  
61  
62  /**
63   * This Service build the portal menu
64   */
65  public final class PortalMenuService extends AbstractCacheableService implements PageEventListener
66  {
67      public static final int MENU_INIT = 0;
68      public static final int MENU_MAIN = 1;
69      public static final int MODE_NORMAL = 0;
70      public static final int MODE_ADMIN = 1;
71      private static final int PORTAL_COMPONENT_MENU_INIT_ID = 3;
72      private static final int PORTAL_COMPONENT_MAIN_MENU_ID = 4;
73      private static final String SERVICE_NAME = "PortalMenuService";
74  
75      // Menus cache
76      private static PortalMenuService _singleton;
77  
78      /** Creates a new instance of PortalMenuService */
79      private PortalMenuService(  )
80      {
81          initCache( getName(  ) );
82          PageService.addPageEventListener( this );
83      }
84  
85      /**
86       * Get the unique instance of the service
87       * @return The unique instance
88       */
89      public static synchronized PortalMenuService getInstance(  )
90      {
91          if ( _singleton == null )
92          {
93              _singleton = new PortalMenuService(  );
94          }
95  
96          return _singleton;
97      }
98  
99      /**
100      * Returns the service name
101      * @return The service name
102      */
103     public String getName(  )
104     {
105         return SERVICE_NAME;
106     }
107 
108     /**
109      * Returns the menu bar from the cache or builds it if it not stored in it
110      * @param request The HTTP request
111      * @param nMode The selected mode
112      * @param nPart The part of the menu to build
113      * @param nCurrentPageId The current page ID
114      * @return The list of the menus layed out with the stylesheet correpsonding to the mode
115      */
116     public String getMenuContent( int nCurrentPageId, int nMode, int nPart, HttpServletRequest request )
117     {
118         String strKey = getKey( nMode, nPart, request );
119         String strMenu = (String) getFromCache( strKey );
120 
121         // Seek for the key in the cache
122         if ( strMenu == null )
123         {
124             // Builds the HTML document
125             strMenu = buildMenuContent( nCurrentPageId, nMode, nPart, request );
126 
127             // Add it in the cache
128             putInCache( strKey, strMenu );
129 
130             return strMenu;
131         }
132 
133         // The document exist in the cache
134         return strMenu;
135     }
136 
137     /**
138      * Builds the menu bar
139      *
140      * @param nCurrentPageId The current page ID
141      * @param nMode The selected mode
142      * @param nPart The part of the menu to build
143      * @param request The HttpServletRequest
144      * @return The list of the menus layed out with the stylesheet of the mode
145      */
146     private String buildMenuContent( int nCurrentPageId, int nMode, int nPart, HttpServletRequest request )
147     {
148         StringBuffer strXml = new StringBuffer(  );
149         Collection<Page> listPagesMenu = PageHome.getChildPagesMinimalData( PortalService.getRootPageId(  ) );
150 
151         String strCurrentPageId = Integer.toString( nCurrentPageId );
152 
153         strXml.append( XmlUtil.getXmlHeader(  ) );
154         XmlUtil.beginElement( strXml, XmlContent.TAG_MENU_LIST );
155 
156         int nMenuIndex = 1;
157 
158         for ( Page menuPage : listPagesMenu )
159         {
160             if ( ( menuPage.isVisible( request ) ) || ( nMode == MODE_ADMIN ) )
161             {
162                 //strCurrentPageId = request.getParameter( PARAMETER_PAGE_ID );
163                 XmlUtil.beginElement( strXml, XmlContent.TAG_MENU );
164                 XmlUtil.addElement( strXml, XmlContent.TAG_MENU_INDEX, nMenuIndex );
165                 XmlUtil.addElement( strXml, XmlContent.TAG_PAGE_ID, menuPage.getId(  ) );
166                 XmlUtil.addElementHtml( strXml, XmlContent.TAG_PAGE_NAME, menuPage.getName(  ) );
167                 XmlUtil.addElementHtml( strXml, XmlContent.TAG_CURRENT_PAGE_ID, strCurrentPageId );
168 
169                 Collection<Page> listSubLevelMenuPages = PageHome.getChildPagesMinimalData( menuPage.getId(  ) );
170 
171                 // add element submenu-list only if list not empty
172                 if ( !listSubLevelMenuPages.isEmpty(  ) )
173                 {
174                     // Seek of the sub-menus
175                     XmlUtil.beginElement( strXml, XmlContent.TAG_SUBLEVEL_MENU_LIST );
176 
177                     int nSubLevelMenuIndex = 1;
178 
179                     for ( Page subLevelMenuPage : listSubLevelMenuPages )
180                     {
181                         if ( ( subLevelMenuPage.isVisible( request ) ) || ( nMode == MODE_ADMIN ) )
182                         {
183                             XmlUtil.beginElement( strXml, XmlContent.TAG_SUBLEVEL_MENU );
184                             XmlUtil.addElement( strXml, XmlContent.TAG_MENU_INDEX, nMenuIndex );
185                             XmlUtil.addElement( strXml, XmlContent.TAG_SUBLEVEL_INDEX, nSubLevelMenuIndex );
186                             XmlUtil.addElement( strXml, XmlContent.TAG_PAGE_ID, subLevelMenuPage.getId(  ) );
187                             XmlUtil.addElementHtml( strXml, XmlContent.TAG_PAGE_NAME, subLevelMenuPage.getName(  ) );
188                             XmlUtil.endElement( strXml, XmlContent.TAG_SUBLEVEL_MENU );
189                             XmlUtil.addElementHtml( strXml, XmlContent.TAG_CURRENT_PAGE_ID, strCurrentPageId );
190                         }
191                     }
192 
193                     XmlUtil.endElement( strXml, XmlContent.TAG_SUBLEVEL_MENU_LIST );
194                 }
195 
196                 XmlUtil.endElement( strXml, XmlContent.TAG_MENU );
197                 nMenuIndex++;
198             }
199         }
200 
201         XmlUtil.endElement( strXml, XmlContent.TAG_MENU_LIST );
202 
203         // Added in v1.3
204         // Use the same stylesheet for normal or admin mode
205         StyleSheet xslSource;
206 
207         // Selection of the XSL stylesheet
208         switch ( nMode )
209         {
210             case MODE_NORMAL:
211             case MODE_ADMIN:
212                 xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_MAIN_MENU_ID, MODE_NORMAL );
213 
214                 break;
215 
216             default:
217                 xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_MAIN_MENU_ID, nMode );
218 
219                 break;
220         }
221 
222         if ( nPart == MENU_INIT )
223         {
224             switch ( nMode )
225             {
226                 case MODE_NORMAL:
227                 case MODE_ADMIN:
228                     xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_MENU_INIT_ID, MODE_NORMAL );
229 
230                     break;
231 
232                 default:
233                     xslSource = PortalComponentHome.getXsl( PORTAL_COMPONENT_MENU_INIT_ID, nMode );
234 
235                     break;
236             }
237         }
238 
239         Properties outputProperties = ModeHome.getOuputXslProperties( nMode );
240 
241         // Added in v1.3
242         // Add a path param for choose url to use in admin or normal mode
243         Map<String, String> mapParamRequest = new HashMap<String, String>(  );
244         PortalService.setXslPortalPath( mapParamRequest, nMode );
245 
246         XmlTransformerService xmlTransformerService = new XmlTransformerService(  );
247 
248         return xmlTransformerService.transformBySourceWithXslCache( strXml.toString(  ), xslSource, mapParamRequest,
249             outputProperties );
250     }
251 
252     /**
253      * Returns the key corresponding to the part according to the selected mode
254      *
255      * @param nMode The mode
256      * @param nPart the part
257      * @param request The HTTP request
258      * @return The key as a String
259      */
260     private String getKey( int nMode, int nPart, HttpServletRequest request )
261     {
262         String strRoles = "-";
263 
264         if ( SecurityService.isAuthenticationEnable(  ) )
265         {
266             if ( request != null )
267             {
268                 LuteceUser user = SecurityService.getInstance(  ).getRegisteredUser( request );
269 
270                 if ( ( user != null ) && ( user.getRoles(  ) != null ) )
271                 {
272                     String[] roles = user.getRoles(  );
273                     Arrays.sort( roles );
274                     strRoles = StringUtils.join( roles, ',' );
275                 }
276             }
277         }
278 
279         StringBuilder sbKey = new StringBuilder(  );
280         sbKey.append( "[menu:" ).append( nPart ).append( "][m:" ).append( nMode ).append( "][roles:" ).append( strRoles )
281              .append( ']' );
282 
283         return sbKey.toString(  );
284     }
285 
286     @Override
287     public void processPageEvent( PageEvent event )
288     {
289         // page was added, removed or updated; clear cache
290         resetCache(  );
291     }
292 }