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.web.system;
35  
36  import fr.paris.lutece.portal.business.portlet.PortletType;
37  import fr.paris.lutece.portal.business.portlet.PortletTypeHome;
38  import fr.paris.lutece.portal.service.admin.AdminUserService;
39  import fr.paris.lutece.portal.service.database.AppConnectionService;
40  import fr.paris.lutece.portal.service.i18n.I18nService;
41  import fr.paris.lutece.portal.service.init.AppInfo;
42  import fr.paris.lutece.portal.service.message.AdminMessage;
43  import fr.paris.lutece.portal.service.message.AdminMessageService;
44  import fr.paris.lutece.portal.service.plugin.Plugin;
45  import fr.paris.lutece.portal.service.plugin.PluginService;
46  import fr.paris.lutece.portal.service.template.AppTemplateService;
47  import fr.paris.lutece.portal.service.util.AppLogService;
48  import fr.paris.lutece.portal.web.admin.AdminFeaturesPageJspBean;
49  import fr.paris.lutece.util.ReferenceList;
50  import fr.paris.lutece.util.html.HtmlTemplate;
51  
52  import java.util.ArrayList;
53  import java.util.Collection;
54  import java.util.HashMap;
55  import java.util.Locale;
56  
57  import javax.servlet.ServletContext;
58  import javax.servlet.http.HttpServletRequest;
59  
60  
61  /**
62   * This class provides the user interface to manage the lutece plugins
63   * (install, enable, disable)
64   */
65  public class PluginJspBean extends AdminFeaturesPageJspBean
66  {
67      ////////////////////////////////////////////////////////////////////////////////
68      // Constants
69      public static final String RIGHT_MANAGE_PLUGINS = "CORE_PLUGINS_MANAGEMENT";
70      private static final long serialVersionUID = -9058113426951331118L;
71      private static final String TEMPLATE_MANAGE_PLUGINS = "admin/system/manage_plugins.html";
72      private static final String MARK_PLUGINS_LIST = "plugins_list";
73      private static final String MARK_CORE = "core";
74      private static final String MARK_POOLS_LIST = "pools_list";
75      private static final String MARK_FILTER_LIST = "filter_list";
76      private static final String MARK_CURRENT_FILTER = "current_filter";
77      private static final String PROPERTY_PLUGIN_MESSAGE = "portal.system.message.confirmDisable";
78      private static final String PROPERTY_PLUGIN_PORTLET_EXIST_MESSAGE = "portal.system.message.portletExist";
79      private static final String PROPERTY_PLUGIN_NO_CORE_COMPATIBILITY_MESSAGE = "portal.system.message.noCoreCompatibility";
80      private static final String PROPERTY_PLUGIN_INSTALL_ERROR = "portal.system.message.installError";
81      private static final String PARAM_PLUGIN_NAME = "plugin_name";
82      private static final String PARAM_PLUGIN_TYPE = "plugin_type";
83      private static final String PARAM_DB_POOL_NAME = "db_pool_name";
84      private static final String PARAM_PLUGIN_TYPE_ALL = "all";
85      private static final String PARAM_PLUGIN_TYPE_PORTLET = "portlet";
86      private static final String PARAM_PLUGIN_TYPE_APPLICATION = "application";
87      private static final String PARAM_PLUGIN_TYPE_FEATURE = "feature";
88      private static final String PARAM_PLUGIN_TYPE_INSERTSERVICE = "insertservice";
89      private static final String PARAM_PLUGIN_TYPE_CONTENTSERVICE = "contentservice";
90      private static final String PROPERTY_PLUGIN_TYPE_NAME_ALL = "portal.system.pluginType.name.all";
91      private static final String PROPERTY_PLUGIN_TYPE_NAME_APPLICATION = "portal.system.pluginType.name.application";
92      private static final String PROPERTY_PLUGIN_TYPE_NAME_PORTLET = "portal.system.pluginType.name.portlet";
93      private static final String PROPERTY_PLUGIN_TYPE_NAME_FEATURE = "portal.system.pluginType.name.feature";
94      private static final String PROPERTY_PLUGIN_TYPE_NAME_INSERTSERVICE = "portal.system.pluginType.name.insertService";
95      private static final String PROPERTY_PLUGIN_TYPE_NAME_CONTENTSERVICE = "portal.system.pluginType.name.contentService";
96      private static final String TEMPLATE_PLUGIN_DETAILS = "/admin/system/view_plugin.html";
97  
98      /**
99       * Returns the plugins management page
100      *
101      * @param request The Http request
102      * @return Html page
103      */
104     public String getManagePlugins( HttpServletRequest request )
105     {
106         Locale locale = AdminUserService.getLocale( request );
107         String strPluginTypeFilter = request.getParameter( PARAM_PLUGIN_TYPE );
108         Collection<Plugin> listPlugins = PluginService.getPluginList(  );
109         HashMap<String, Object> model = new HashMap<String, Object>(  );
110         model.put( MARK_PLUGINS_LIST, filterPluginsList( listPlugins, strPluginTypeFilter ) );
111         model.put( MARK_CORE, PluginService.getCore( ) );
112         model.put( MARK_POOLS_LIST, getPoolsList(  ) );
113         model.put( MARK_FILTER_LIST, getPluginTypeFilterList( locale ) );
114         model.put( MARK_CURRENT_FILTER, ( strPluginTypeFilter != null ) ? strPluginTypeFilter : "" );
115 
116         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_MANAGE_PLUGINS, locale, model );
117 
118         return getAdminPage( template.getHtml(  ) );
119     }
120 
121     /**
122      * Install a plugin
123      *
124      * @param request The Http request
125      * @param context The servlet context
126      * @return the url of the page containing a log essage
127      */
128     public String doInstallPlugin( HttpServletRequest request, ServletContext context )
129     {
130         try
131         {
132             String strPluginName = request.getParameter( PARAM_PLUGIN_NAME );
133             Plugin plugin = PluginService.getPlugin( strPluginName );
134 
135             if ( verifyCoreCompatibility( plugin ) )
136             {
137                 plugin.install(  );
138             }
139             else
140             {
141                 Object[] args = { plugin.getMinCoreVersion(  ), plugin.getMaxCoreVersion(  ) };
142 
143                 return AdminMessageService.getMessageUrl( request, PROPERTY_PLUGIN_NO_CORE_COMPATIBILITY_MESSAGE, args,
144                     AdminMessage.TYPE_STOP );
145             }
146         }
147         catch ( Exception e )
148         {
149             AppLogService.error( e.getMessage(  ), e );
150 
151             return AdminMessageService.getMessageUrl( request, PROPERTY_PLUGIN_INSTALL_ERROR, AdminMessage.TYPE_STOP );
152         }
153 
154         return getHomeUrl( request );
155     }
156 
157     /**
158      * Uninstall a plugin
159      *
160      * @param request The Http request
161      * @param context The servlet context
162      * @return the url of the page containing a log essage
163      */
164     public String doUninstallPlugin( HttpServletRequest request, ServletContext context )
165     {
166         try
167         {
168             String strPluginName = request.getParameter( PARAM_PLUGIN_NAME );
169             Plugin plugin = PluginService.getPlugin( strPluginName );
170             plugin.uninstall(  );
171         }
172         catch ( Exception e )
173         {
174             AppLogService.error( e.getMessage(  ), e );
175         }
176 
177         return getHomeUrl( request );
178     }
179 
180     /**
181      * Returns the page of confirmation for uninstalling a plugin
182      *
183      * @param request The Http Request
184      * @return the HTML page
185      */
186     public String getConfirmUninstallPlugin( HttpServletRequest request )
187     {
188         String strPluginName = request.getParameter( PARAM_PLUGIN_NAME );
189         Plugin plugin = PluginService.getPlugin( strPluginName );
190         Collection<PortletType> listPortletTypes = plugin.getPortletTypes(  );
191         String strMessageKey = PROPERTY_PLUGIN_MESSAGE;
192         String strUrl = "jsp/admin/system/DoUninstallPlugin.jsp?plugin_name=" + strPluginName;
193         String strAdminMessageUrl = AdminMessageService.getMessageUrl( request, strMessageKey, strUrl, "",
194                 AdminMessage.TYPE_CONFIRMATION );
195 
196         for ( PortletType portletType : listPortletTypes )
197         {
198             String strPluginHomeClass = portletType.getHomeClass(  );
199 
200             if ( ( plugin.getType(  ) & Plugin.PLUGIN_TYPE_PORTLET ) != 0 )
201             {
202                 if ( isPortletExists( strPluginHomeClass ) )
203                 {
204                     strMessageKey = PROPERTY_PLUGIN_PORTLET_EXIST_MESSAGE;
205                     strAdminMessageUrl = AdminMessageService.getMessageUrl( request, strMessageKey,
206                             AdminMessage.TYPE_CONFIRMATION );
207                 }
208             }
209         }
210 
211         return strAdminMessageUrl;
212     }
213 
214     /**
215      * Defines the database connection pool to be used by the plugin
216      * @param request The http request
217      * @return the URL to redirect after this action
218      */
219     public String doModifyPluginPool( HttpServletRequest request )
220     {
221         String strPluginName = request.getParameter( PARAM_PLUGIN_NAME );
222         String strDbPoolName = request.getParameter( PARAM_DB_POOL_NAME );
223 
224         try
225         {
226             Plugin plugin = PluginService.getPlugin( strPluginName );
227             plugin.updatePoolName( strDbPoolName );
228         }
229         catch ( Exception e )
230         {
231             AppLogService.error( e.getMessage(  ), e );
232         }
233 
234         return getHomeUrl( request );
235     }
236 
237     /**
238      * Displays a plugin's description
239      * @param request The HTTP request
240      * @return The popup HTML code
241      */
242     public String getPluginDescription( HttpServletRequest request )
243     {
244         String strPluginName = request.getParameter( PARAM_PLUGIN_NAME );
245         Plugin plugin;
246         if ( PluginService.getCore( ).getName( ).equals( strPluginName ) )
247         {
248             plugin = PluginService.getCore( );
249         } else
250         {
251             plugin = PluginService.getPlugin( strPluginName );
252         }
253 
254         // set the locale for the feature labels
255         I18nService.localizeCollection( plugin.getRights(  ), getLocale(  ) );
256         // set the locale for the portlet types labels
257         I18nService.localizeCollection( plugin.getPortletTypes(  ), getLocale(  ) );
258         // set the locale for the  link services labels
259         I18nService.localizeCollection( plugin.getInsertServices(  ), getLocale(  ) );
260 
261         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_PLUGIN_DETAILS, getLocale(  ), plugin );
262 
263         return getAdminPage( template.getHtml(  ) );
264     }
265 
266     //////////////////////////////////////////////////////////////////////////////////////////////////////////
267     // Private implementation
268 
269     /**
270      * Return a filter list of plugins
271      * @param listPlugins the COllection of plugins
272      * @param strPluginTypeFilter The filter
273      * @return list The list of plugins
274      */
275     private Collection<Plugin> filterPluginsList( Collection<Plugin> listPlugins, String strPluginTypeFilter )
276     {
277         Collection<Plugin> list = new ArrayList<Plugin>(  );
278 
279         for ( Plugin plugin : listPlugins )
280         {
281             // Checks for filtering the plugin list
282             if ( strPluginTypeFilter != null )
283             {
284                 if ( strPluginTypeFilter.equals( PARAM_PLUGIN_TYPE_APPLICATION ) &&
285                         ( ( plugin.getType(  ) & Plugin.PLUGIN_TYPE_APPLICATION ) == 0 ) )
286                 {
287                     // skip this plugin
288                     continue;
289                 }
290 
291                 if ( strPluginTypeFilter.equals( PARAM_PLUGIN_TYPE_PORTLET ) &&
292                         ( ( plugin.getType(  ) & Plugin.PLUGIN_TYPE_PORTLET ) == 0 ) )
293                 {
294                     // skip this plugin
295                     continue;
296                 }
297 
298                 if ( strPluginTypeFilter.equals( PARAM_PLUGIN_TYPE_FEATURE ) &&
299                         ( ( plugin.getType(  ) & Plugin.PLUGIN_TYPE_FEATURE ) == 0 ) )
300                 {
301                     // skip this plugin
302                     continue;
303                 }
304 
305                 if ( strPluginTypeFilter.equals( PARAM_PLUGIN_TYPE_INSERTSERVICE ) &&
306                         ( ( plugin.getType(  ) & Plugin.PLUGIN_TYPE_INSERTSERVICE ) == 0 ) )
307                 {
308                     // skip this plugin
309                     continue;
310                 }
311 
312                 if ( strPluginTypeFilter.equals( PARAM_PLUGIN_TYPE_CONTENTSERVICE ) &&
313                         ( ( plugin.getType(  ) & Plugin.PLUGIN_TYPE_CONTENTSERVICE ) == 0 ) )
314                 {
315                     // skip this plugin
316                     continue;
317                 }
318             }
319 
320             list.add( plugin );
321         }
322 
323         return list;
324     }
325 
326     /**
327      * Create a ReferenceList containing all Plugin types
328      * @param locale The Locale
329      * @return A ReferenceList containing all Plugin types
330      */
331     private ReferenceList getPluginTypeFilterList( Locale locale )
332     {
333         ReferenceList list = new ReferenceList(  );
334         list.addItem( PARAM_PLUGIN_TYPE_ALL, I18nService.getLocalizedString( PROPERTY_PLUGIN_TYPE_NAME_ALL, locale ) );
335         list.addItem( PARAM_PLUGIN_TYPE_APPLICATION,
336             I18nService.getLocalizedString( PROPERTY_PLUGIN_TYPE_NAME_APPLICATION, locale ) );
337         list.addItem( PARAM_PLUGIN_TYPE_PORTLET,
338             I18nService.getLocalizedString( PROPERTY_PLUGIN_TYPE_NAME_PORTLET, locale ) );
339         list.addItem( PARAM_PLUGIN_TYPE_FEATURE,
340             I18nService.getLocalizedString( PROPERTY_PLUGIN_TYPE_NAME_FEATURE, locale ) );
341         list.addItem( PARAM_PLUGIN_TYPE_INSERTSERVICE,
342             I18nService.getLocalizedString( PROPERTY_PLUGIN_TYPE_NAME_INSERTSERVICE, locale ) );
343         list.addItem( PARAM_PLUGIN_TYPE_CONTENTSERVICE,
344             I18nService.getLocalizedString( PROPERTY_PLUGIN_TYPE_NAME_CONTENTSERVICE, locale ) );
345 
346         return list;
347     }
348 
349     /**
350      * Return a list of pools
351      * @return listPools the list of pools
352      */
353     private ReferenceList getPoolsList(  )
354     {
355         ReferenceList listPools = new ReferenceList(  );
356         listPools.addItem( AppConnectionService.NO_POOL_DEFINED, " " );
357         AppConnectionService.getPoolList( listPools );
358 
359         return listPools;
360     }
361 
362     /**
363      * Returns the status of the existence of a portlet on the site
364      *
365      * @param strPluginHomeClass The home class of the plugin
366      * @return The existence status as a boolean
367      */
368     private boolean isPortletExists( String strPluginHomeClass )
369     {
370         String strPortletTypeId = PortletTypeHome.getPortletTypeId( strPluginHomeClass );
371 
372         return ( PortletTypeHome.getNbPortletTypeByPortlet( strPortletTypeId ) != 0 );
373     }
374 
375     /**
376      * Verify the core compatibility for a plugin
377      *
378      * @param plugin The plugin
379      * @return true if compatible with the current core version
380      */
381     private boolean verifyCoreCompatibility( Plugin plugin )
382     {
383         String strCoreVersion = AppInfo.getVersion(  );
384 
385         // Remove version qualifier (-SNAPSHOT, -RC-XX, ...)
386         int nPos = strCoreVersion.indexOf( "-" );
387 
388         if ( nPos > 0 )
389         {
390             strCoreVersion = strCoreVersion.substring( 0, nPos );
391         }
392 
393         String[] coreVersion = strCoreVersion.split( "\\." );
394 
395         String strMinCoreVersion = ( plugin.getMinCoreVersion(  ) == null ) ? "" : plugin.getMinCoreVersion(  );
396         String strMaxCoreVersion = ( plugin.getMaxCoreVersion(  ) == null ) ? "" : plugin.getMaxCoreVersion(  );
397 
398         // test the min core version
399         boolean bMin = ( strMinCoreVersion == null ) || strMinCoreVersion.trim(  ).equals( "" );
400 
401         if ( ( strMinCoreVersion != null ) && !strMinCoreVersion.trim(  ).equals( "" ) )
402         {
403             String[] minCoreVersion = strMinCoreVersion.split( "\\." );
404 
405             if ( checkCoreMinCompatibility( minCoreVersion, coreVersion ) )
406             {
407                 AppLogService.debug( "Min core version ok : " + plugin.getMinCoreVersion(  ) );
408                 bMin = true;
409             }
410         }
411 
412         // test the max core version
413         boolean bMax = ( strMaxCoreVersion == null ) || strMaxCoreVersion.trim(  ).equals( "" );
414 
415         if ( ( strMaxCoreVersion != null ) && !strMaxCoreVersion.trim(  ).equals( "" ) )
416         {
417             String[] maxCoreVersion = strMaxCoreVersion.split( "\\." );
418 
419             if ( checkCoreMaxCompatibility( maxCoreVersion, coreVersion ) )
420             {
421                 AppLogService.debug( "Max core version ok : " + plugin.getMaxCoreVersion(  ) );
422                 bMax = true;
423             }
424         }
425 
426         return bMin && bMax;
427     }
428 
429     /**
430      * Checks the compatibility
431      * @param minCoreVersion The min core version
432      * @param coreVersion The current core version
433      * @return true if compatible with the current core version
434      */
435     private boolean checkCoreMinCompatibility( String[] minCoreVersion, String[] coreVersion )
436     {
437         for ( int i = 0; i < Math.min( minCoreVersion.length, coreVersion.length ); ++i )
438         {
439             if ( ( Integer.parseInt( minCoreVersion[i] ) ) < ( Integer.parseInt( coreVersion[i] ) ) )
440             {
441                 return true;
442             }
443 
444             if ( ( Integer.parseInt( minCoreVersion[i] ) ) > ( Integer.parseInt( coreVersion[i] ) ) )
445             {
446                 return false;
447             }
448         }
449 
450         return true; //inclusive
451     }
452 
453     /**
454      * Checks the compatibility
455      * @param maxCoreVersion The max core version
456      * @param coreVersion The current core version
457      * @return true if compatible with the current core version
458      */
459     private boolean checkCoreMaxCompatibility( String[] maxCoreVersion, String[] coreVersion )
460     {
461         for ( int i = 0; i < Math.min( maxCoreVersion.length, coreVersion.length ); ++i )
462         {
463             if ( ( Integer.parseInt( maxCoreVersion[i] ) ) > ( Integer.parseInt( coreVersion[i] ) ) )
464             {
465                 return true;
466             }
467 
468             if ( ( Integer.parseInt( maxCoreVersion[i] ) ) < ( Integer.parseInt( coreVersion[i] ) ) )
469             {
470                 return false;
471             }
472         }
473 
474         return false; //exclusive
475     }
476 }