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.content;
35  
36  import fr.paris.lutece.portal.service.init.LuteceInitException;
37  import fr.paris.lutece.portal.service.message.SiteMessage;
38  import fr.paris.lutece.portal.service.message.SiteMessageException;
39  import fr.paris.lutece.portal.service.message.SiteMessageService;
40  import fr.paris.lutece.portal.service.portal.PortalService;
41  import fr.paris.lutece.portal.service.security.LuteceUser;
42  import fr.paris.lutece.portal.service.security.SecurityService;
43  import fr.paris.lutece.portal.service.security.UserNotSignedException;
44  import fr.paris.lutece.portal.service.spring.SpringContextService;
45  import fr.paris.lutece.portal.service.template.AppTemplateService;
46  import fr.paris.lutece.portal.service.util.AppException;
47  import fr.paris.lutece.portal.service.util.AppLogService;
48  import fr.paris.lutece.portal.web.xpages.XPage;
49  import fr.paris.lutece.portal.web.xpages.XPageApplication;
50  import fr.paris.lutece.portal.web.xpages.XPageApplicationEntry;
51  import fr.paris.lutece.util.html.HtmlTemplate;
52  
53  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
54  
55  import java.util.Collection;
56  import java.util.HashMap;
57  import java.util.List;
58  import java.util.Map;
59  
60  import javax.servlet.http.HttpServletRequest;
61  import javax.servlet.http.HttpSession;
62  
63  
64  /**
65   * This class delivers Extra pages (xpages) to web components. An XPage is a page where the content is provided by a
66   * specific class, but should be integrated into the portal struture and design. XPageApps are identified by a key
67   * name.
68   * To display an XPage into the portal just call the following url :<br><code>
69   * Portal.jsp?page=<i>keyname</i>&amp;param1=value1&amp; ...&amp;paramN=valueN </code>
70   *
71   * @see fr.paris.lutece.portal.web.xpages.XPage
72   */
73  public class XPageAppService extends ContentService
74  {
75      public static final String PARAM_XPAGE_APP = "page";
76      private static final String CONTENT_SERVICE_NAME = "XPageAppService";
77      private static final String MESSAGE_ERROR_APP_BODY = "portal.util.message.errorXpageApp";
78      private static final String ATTRIBUTE_XPAGE = "LUTECE_XPAGE_";
79      private static Map<String, XPageApplicationEntry> _mapApplications = new HashMap<String, XPageApplicationEntry>(  );
80  
81      /**
82       * Register an application by its entry defined in the plugin xml file
83       * @param entry The application entry
84       * @throws LuteceInitException If an error occured
85       */
86      public static void registerXPageApplication( XPageApplicationEntry entry )
87          throws LuteceInitException
88      {
89          try
90          {
91              if ( entry.getClassName(  ) == null )
92              {
93                  String applicationBeanName = entry.getPluginName(  ) + ".xpage." + entry.getId(  );
94  
95                  if ( !SpringContextService.getContext(  ).containsBean( applicationBeanName ) )
96                  {
97                      throw new LuteceInitException( "Error instantiating XPageApplication : " + entry.getId(  ) +
98                          " - Could not find bean named " + applicationBeanName,
99                          new NoSuchBeanDefinitionException( applicationBeanName ) );
100                 }
101             }
102             else
103             {
104                 // check that the class can be found
105                 Class.forName( entry.getClassName(  ) ).newInstance(  );
106             }
107 
108             _mapApplications.put( entry.getId(  ), entry );
109             AppLogService.info( "New XPage application registered : " + entry.getId(  )
110                     + ( entry.isEnabled(  ) ? "" : " (disabled)" ) );
111         }
112         catch ( ClassNotFoundException e )
113         {
114             throw new LuteceInitException( "Error instantiating XPageApplication : " + entry.getId(  ) + " - " +
115                 e.getCause(  ), e );
116         }
117         catch ( InstantiationException e )
118         {
119             throw new LuteceInitException( "Error instantiating XPageApplication : " + entry.getId(  ) + " - " +
120                 e.getCause(  ), e );
121         }
122         catch ( IllegalAccessException e )
123         {
124             throw new LuteceInitException( "Error instantiating XPageApplication : " + entry.getId(  ) + " - " +
125                 e.getCause(  ), e );
126         }
127     }
128 
129     /**
130      * Returns the Content Service name
131      *
132      * @return The name as a String
133      */
134     @Override
135     public String getName(  )
136     {
137         return CONTENT_SERVICE_NAME;
138     }
139 
140     /**
141      * Analyzes request parameters to see if the request should be handled by the current Content Service
142      *
143      * @param request The HTTP request
144      * @return true if this ContentService should handle this request
145      */
146     @Override
147     public boolean isInvoked( HttpServletRequest request )
148     {
149         String strXPage = request.getParameter( PARAM_XPAGE_APP );
150 
151         if ( ( strXPage != null ) && ( strXPage.length(  ) > 0 ) )
152         {
153             return true;
154         }
155 
156         return false;
157     }
158 
159     /**
160      * Enable or disable the cache feature.
161      *
162      * @param bCache true to enable the cache, false to disable
163      */
164     public void setCache( boolean bCache )
165     {
166     }
167 
168     /**
169      * Gets the current cache status.
170      *
171      * @return true if enable, otherwise false
172      */
173     @Override
174     public boolean isCacheEnable(  )
175     {
176         return false;
177     }
178 
179     /**
180      * Reset the cache.
181      */
182     @Override
183     public void resetCache(  )
184     {
185     }
186 
187     /**
188      * Gets the number of item currently in the cache.
189      *
190      * @return the number of item currently in the cache.
191      */
192     @Override
193     public int getCacheSize(  )
194     {
195         return 0;
196     }
197 
198     /**
199      * Build the XPage content.
200      *
201      * @param request The HTTP request.
202      * @param nMode The current mode.
203      * @return The HTML code of the page.
204      * @throws UserNotSignedException The User Not Signed Exception
205      * @throws SiteMessageException occurs when a site message need to be displayed
206      */
207     @Override
208     public String getPage( HttpServletRequest request, int nMode )
209         throws UserNotSignedException, SiteMessageException
210     {
211         // Gets XPage info from the lutece.properties
212         String strName = request.getParameter( PARAM_XPAGE_APP );
213 
214         XPageApplicationEntry entry = getApplicationEntry( strName );
215 
216         // TODO : Handle entry == null
217         if ( ( entry != null ) && ( entry.isEnable(  ) ) )
218         {
219             XPage page = null;
220             List<String> listRoles = entry.getRoles(  );
221 
222             if ( SecurityService.isAuthenticationEnable(  ) && ( listRoles.size(  ) > 0 ) )
223             {
224                 LuteceUser user = SecurityService.getInstance(  ).getRegisteredUser( request );
225 
226                 if ( user != null )
227                 {
228                     boolean bAutorized = false;
229 
230                     for ( String strRole : listRoles )
231                     {
232                         if ( SecurityService.getInstance(  ).isUserInRole( request, strRole ) )
233                         {
234                             bAutorized = true;
235                         }
236                     }
237 
238                     if ( bAutorized )
239                     {
240                         XPageApplication application = getXPageSessionInstance( request, entry );
241                         page = application.getPage( request, nMode, entry.getPlugin(  ) );
242                     }
243                     else
244                     {
245                         // The user doesn't have the correct role
246                         String strAccessDeniedTemplate = SecurityService.getInstance(  ).getAccessDeniedTemplate(  );
247                         HtmlTemplate tAccessDenied = AppTemplateService.getTemplate( strAccessDeniedTemplate );
248                         page = new XPage(  );
249                         page.setContent( tAccessDenied.getHtml(  ) );
250                     }
251                 }
252                 else
253                 {
254                     throw new UserNotSignedException(  );
255                 }
256             }
257             else
258             {
259                 XPageApplication application = getXPageSessionInstance( request, entry );
260                 page = application.getPage( request, nMode, entry.getPlugin(  ) );
261             }
262 
263             if ( page.isStandalone(  ) )
264             {
265                 return page.getContent(  );
266             }
267 
268             PageData data = new PageData(  );
269 
270             data.setContent( page.getContent(  ) );
271             data.setName( page.getTitle(  ) );
272 
273             // set the page path. Done by adding the extra-path information to the pathLabel.
274             String strXml = page.getXmlExtendedPathLabel(  );
275 
276             if ( strXml == null )
277             {
278                 data.setPagePath( PortalService.getXPagePathContent( page.getPathLabel(  ), 0, request ) );
279             }
280             else
281             {
282                 data.setPagePath( PortalService.getXPagePathContent( page.getPathLabel(  ), 0, strXml, request ) );
283             }
284 
285             return PortalService.buildPageContent( data, nMode, request );
286         }
287         else
288         {
289             AppLogService.error( "The specified Xpage '" + strName +
290                 "' cannot be retrieved. Check installation of your Xpage application." );
291             SiteMessageService.setMessage( request, MESSAGE_ERROR_APP_BODY, SiteMessage.TYPE_ERROR );
292 
293             return null; // unreachable because SiteMessageService.setMessage throws
294         }
295     }
296 
297     /**
298      * Gets Application entry by name
299      * @param strName The application's name
300      * @return The entry
301      */
302     public static XPageApplicationEntry getApplicationEntry( String strName )
303     {
304         return _mapApplications.get( strName );
305     }
306 
307     /**
308      * Gets applications list
309      * @return A collection of applications
310      */
311     public static Collection<XPageApplicationEntry> getXPageApplicationsList(  )
312     {
313         return _mapApplications.values(  );
314     }
315 
316     /**
317      * Return an instance of the XPage attached to the current Http Session
318      * @param request The HTTP request
319      * @param entry The XPage entry
320      * @return The XPage instance
321      */
322     private static XPageApplication getXPageSessionInstance( HttpServletRequest request, XPageApplicationEntry entry )
323     {
324         HttpSession session = request.getSession( true );
325         String strAttribute = ATTRIBUTE_XPAGE + entry.getId(  );
326         XPageApplication application = (XPageApplication) session.getAttribute( strAttribute );
327 
328         if ( application == null )
329         {
330             application = getApplicationInstance( entry );
331             session.setAttribute( strAttribute, application );
332             AppLogService.debug( "New XPage instance of " + entry.getClassName(  ) +
333                 " created and attached to session " + session );
334         }
335 
336         return application;
337     }
338 
339     /**
340      * Get an XPage instance
341      * @param entry The Xpage entry
342      * @return An instance of a given XPage
343      */
344     public static XPageApplication getApplicationInstance( XPageApplicationEntry entry )
345     {
346         XPageApplication application = null;
347 
348         try
349         {
350             if ( entry.getClassName(  ) == null )
351             {
352                 application = SpringContextService.getBean( entry.getPluginName(  ) + ".xpage." + entry.getId(  ) );
353             }
354             else
355             {
356                 application = (XPageApplication) Class.forName( entry.getClassName(  ) ).newInstance(  );
357             }
358         }
359         catch ( Exception e )
360         {
361             throw new AppException( "Error instantiating XPageApplication : " + entry.getId(  ) + " - " +
362                 e.getCause(  ), e );
363         }
364 
365         return application;
366     }
367 }