Back to index

plone3  3.1.7
PluginRegistry.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights
00004 # Reserved.
00005 #
00006 # This software is subject to the provisions of the Zope Public License,
00007 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this
00008 # distribution.
00009 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00010 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00011 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00012 # FOR A PARTICULAR PURPOSE
00013 #
00014 ##############################################################################
00015 """ Classes: PluginRegistry
00016 
00017 $Id: PluginRegistry.py 74716 2007-04-24 19:15:04Z tseaver $
00018 """
00019 import logging
00020 
00021 from Globals import Persistent
00022 from App.ImageFile import ImageFile
00023 from Acquisition import Implicit, aq_parent, aq_inner
00024 from AccessControl import ClassSecurityInfo
00025 from AccessControl.Permissions import manage_users as ManageUsers
00026 from Persistence import PersistentMapping
00027 from OFS.SimpleItem import SimpleItem
00028 from App.class_init import default__class_init__ as InitializeClass
00029 
00030 try:
00031     from webdav.interfaces import IWriteLock
00032 except ImportError:
00033     try:
00034         from Products.Five.interfaces import IWriteLock
00035     except ImportError:
00036         _HAS_Z3_DAV_INTERFACES = False
00037         from webdav.WriteLockInterface import WriteLockInterface
00038     else:
00039         _HAS_Z3_DAV_INTERFACES = True
00040 else:
00041     _HAS_Z3_DAV_INTERFACES = True
00042 
00043 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
00044 from Products.PageTemplates.Expressions import getEngine
00045 from Products.PageTemplates.Expressions import SecureModuleImporter
00046 
00047 from interfaces import IPluginRegistry
00048 from interfaces import _HAS_Z3_INTERFACES
00049 if _HAS_Z3_INTERFACES:
00050     from zope.interface import implements
00051 
00052 try:
00053     from exportimport import _updatePluginRegistry
00054 except ImportError:
00055     _HAS_GENERIC_SETUP = False
00056 else:
00057     _HAS_GENERIC_SETUP = True
00058 
00059 from utils import _wwwdir
00060 
00061 logger = logging.getLogger('PluginRegistry')
00062 
00063 class PluginRegistry( SimpleItem ):
00064 
00065     """ Implement IPluginRegistry as an independent, ZMI-manageable object.
00066 
00067     o Each plugin type holds an ordered list of ( id, wrapper ) tuples.
00068     """
00069     if _HAS_Z3_INTERFACES:
00070         if _HAS_Z3_DAV_INTERFACES:
00071             implements(IPluginRegistry, IWriteLock)
00072         else:
00073             implements(IPluginRegistry)
00074             __implements__ = (WriteLockInterface,)
00075     else:
00076         __implements__ = (IPluginRegistry, WriteLockInterface,)
00077 
00078     security = ClassSecurityInfo()
00079 
00080     meta_type = 'Plugin Registry'
00081 
00082     _plugins = None
00083 
00084     def __init__( self, plugin_type_info=() ):
00085 
00086         if isinstance(plugin_type_info, basestring):
00087             # some tool is passing us our ID.
00088             raise ValueError('Must pass a sequence of plugin info dicts!')
00089 
00090         self._plugin_types = [x[0] for x in plugin_type_info]
00091         self._plugin_type_info = PersistentMapping()
00092         for interface in plugin_type_info:
00093             self._plugin_type_info[interface[0]] = { 
00094                   'id': interface[1]
00095                 , 'title': interface[2]
00096                 , 'description': interface[3]
00097                 }
00098 
00099     #
00100     #   IPluginRegistry implementation
00101     #
00102     security.declareProtected( ManageUsers, 'listPluginTypeInfo' )
00103     def listPluginTypeInfo( self ):
00104 
00105         """ See IPluginRegistry.
00106         """
00107         result = []
00108 
00109         for ptype in self._plugin_types:
00110 
00111             info = self._plugin_type_info[ptype].copy()
00112             info['interface'] = ptype
00113             info['methods'] = ptype.names()
00114 
00115             result.append( info )
00116 
00117         return result
00118 
00119     security.declareProtected( ManageUsers, 'listPlugins' )
00120     def listPlugins( self, plugin_type ):
00121 
00122         """ See IPluginRegistry.
00123         """
00124         result = []
00125 
00126         parent = aq_parent( aq_inner( self ) )
00127 
00128         for plugin_id in self._getPlugins( plugin_type ):
00129 
00130             plugin = parent._getOb( plugin_id )
00131             if not _satisfies( plugin, plugin_type ):
00132                 logger.debug( 'Active plugin %s no longer implements %s'
00133                                 % ( plugin_id, plugin_type )
00134                             )
00135             else:
00136                 result.append( ( plugin_id, plugin ) )
00137 
00138         return result
00139 
00140     security.declareProtected( ManageUsers, 'getPluginInfo' )
00141     def getPluginInfo( self, plugin_type ):
00142 
00143         """ See IPluginRegistry.
00144         """
00145         plugin_type = self._getInterfaceFromName( plugin_type )
00146         return self._plugin_type_info[plugin_type]
00147 
00148     security.declareProtected( ManageUsers, 'listPluginIds' )
00149     def listPluginIds( self, plugin_type ):
00150 
00151         """ See IPluginRegistry.
00152         """
00153 
00154         return self._getPlugins( plugin_type )
00155 
00156     security.declareProtected( ManageUsers, 'activatePlugin' )
00157     def activatePlugin( self, plugin_type, plugin_id ):
00158 
00159         """ See IPluginRegistry.
00160         """
00161         plugins = list( self._getPlugins( plugin_type ) )
00162 
00163         if plugin_id in plugins:
00164             raise KeyError, 'Duplicate plugin id: %s' % plugin_id
00165 
00166         parent = aq_parent( aq_inner( self ) )
00167         plugin = parent._getOb( plugin_id ) 
00168 
00169         if not _satisfies(plugin, plugin_type):
00170             raise ValueError, 'Plugin does not implement %s' % plugin_type 
00171         
00172         plugins.append( plugin_id )
00173         self._plugins[ plugin_type ] = tuple( plugins )
00174 
00175     security.declareProtected( ManageUsers, 'deactivatePlugin' )
00176     def deactivatePlugin( self, plugin_type, plugin_id ):
00177 
00178         """ See IPluginRegistry.
00179         """
00180         plugins = list( self._getPlugins( plugin_type ) )
00181 
00182         if not plugin_id in plugins:
00183             raise KeyError, 'Invalid plugin id: %s' % plugin_id
00184 
00185         plugins = [ x for x in plugins if x != plugin_id ]
00186         self._plugins[ plugin_type ] = tuple( plugins )
00187 
00188     security.declareProtected( ManageUsers, 'movePluginsUp' )
00189     def movePluginsUp( self, plugin_type, ids_to_move ):
00190 
00191         """ See IPluginRegistry.
00192         """
00193         ids = list( self._getPlugins( plugin_type ) )
00194         count = len( ids )
00195 
00196         indexes = list( map( ids.index, ids_to_move ) )
00197         indexes.sort()
00198 
00199         for i1 in indexes:
00200 
00201             if i1 < 0 or i1 >= count:
00202                 raise IndexError, i1
00203 
00204             i2 = i1 - 1
00205             if i2 < 0:      # wrap to bottom
00206                 i2 = len( ids ) - 1
00207 
00208             ids[ i2 ], ids[ i1 ] = ids[ i1 ], ids[ i2 ]
00209 
00210         self._plugins[ plugin_type ] = tuple( ids )
00211 
00212     security.declareProtected( ManageUsers, 'movePluginsDown' )
00213     def movePluginsDown( self, plugin_type, ids_to_move ):
00214 
00215         """ See IPluginRegistry.
00216         """
00217         ids = list( self._getPlugins( plugin_type ) )
00218         count = len( ids )
00219 
00220         indexes = list( map( ids.index, ids_to_move ) )
00221         indexes.sort()
00222         indexes.reverse()
00223 
00224         for i1 in indexes:
00225 
00226             if i1 < 0 or i1 >= count:
00227                 raise IndexError, i1
00228 
00229             i2 = i1 + 1
00230             if i2 == len( ids ):      # wrap to top
00231                 i2 = 0
00232 
00233             ids[ i2 ], ids[ i1 ] = ids[ i1 ], ids[ i2 ]
00234 
00235         self._plugins[ plugin_type ] = tuple( ids )
00236 
00237     #
00238     #   ZMI
00239     #
00240     arrow_right_gif = ImageFile( 'www/arrow-right.gif', globals() )
00241     arrow_left_gif = ImageFile( 'www/arrow-left.gif', globals() )
00242     arrow_up_gif = ImageFile( 'www/arrow-up.gif', globals() )
00243     arrow_down_gif = ImageFile( 'www/arrow-down.gif', globals() )
00244 
00245     security.declareProtected( ManageUsers, 'manage_activatePlugins' )
00246     def manage_activatePlugins( self
00247                              , plugin_type
00248                              , plugin_ids
00249                              , RESPONSE
00250                              ):
00251         """ Shim into ZMI.
00252         """
00253         interface = self._getInterfaceFromName( plugin_type )
00254         for id in plugin_ids:
00255             self.activatePlugin( interface, id )
00256         RESPONSE.redirect( '%s/manage_plugins?plugin_type=%s'
00257                          % ( self.absolute_url(), plugin_type )
00258                          )
00259 
00260     security.declareProtected( ManageUsers, 'manage_deactivatePlugins' )
00261     def manage_deactivatePlugins( self
00262                                 , plugin_type
00263                                 , plugin_ids
00264                                 , RESPONSE
00265                                 ):
00266         """ Shim into ZMI.
00267         """
00268         interface = self._getInterfaceFromName( plugin_type )
00269         for id in plugin_ids:
00270             self.deactivatePlugin( interface, id )
00271 
00272         RESPONSE.redirect( '%s/manage_plugins?plugin_type=%s'
00273                          % ( self.absolute_url(), plugin_type )
00274                          )
00275 
00276     security.declareProtected( ManageUsers, 'manage_movePluginsUp' )
00277     def manage_movePluginsUp( self
00278                             , plugin_type
00279                             , plugin_ids
00280                             , RESPONSE
00281                             ):
00282         """ Shim into ZMI.
00283         """
00284         interface = self._getInterfaceFromName( plugin_type )
00285         self.movePluginsUp( interface, plugin_ids )
00286 
00287         RESPONSE.redirect( '%s/manage_plugins?plugin_type=%s'
00288                          % ( self.absolute_url(), plugin_type )
00289                          )
00290 
00291     security.declareProtected( ManageUsers, 'manage_movePluginsDown' )
00292     def manage_movePluginsDown( self
00293                               , plugin_type
00294                               , plugin_ids
00295                               , RESPONSE
00296                               ):
00297         """ Shim into ZMI.
00298         """
00299         interface = self._getInterfaceFromName( plugin_type )
00300         self.movePluginsDown( interface, plugin_ids )
00301 
00302         RESPONSE.redirect( '%s/manage_plugins?plugin_type=%s'
00303                          % ( self.absolute_url(), plugin_type )
00304                          )
00305 
00306     security.declareProtected( ManageUsers, 'getAllPlugins' )
00307     def getAllPlugins( self, plugin_type ):
00308 
00309         """ Return a mapping segregating active / available plugins.
00310 
00311         'plugin_type' is the __name__ of the interface.
00312         """
00313         interface = self._getInterfaceFromName( plugin_type )
00314 
00315         active = self._getPlugins( interface )
00316         available = []
00317 
00318         for id, value in aq_parent( aq_inner( self ) ).objectItems():
00319             if _satisfies(value, interface):
00320                 if id not in active:
00321                     available.append( id )
00322 
00323         return { 'active' : active, 'available' : available }
00324 
00325 
00326     security.declareProtected( ManageUsers, 'removePluginById' )
00327     def removePluginById( self, plugin_id ):
00328 
00329         """ Remove a plugin from any plugin types which have it configured.
00330         """
00331         for plugin_type in self._plugin_types:
00332 
00333             if plugin_id in self._getPlugins( plugin_type ):
00334                 self.deactivatePlugin( plugin_type, plugin_id )
00335 
00336     security.declareProtected( ManageUsers, 'manage_plugins' )
00337     manage_plugins = PageTemplateFile( 'plugins', _wwwdir )
00338     security.declareProtected( ManageUsers, 'manage_active' )
00339     manage_active = PageTemplateFile( 'active_plugins', _wwwdir )
00340     manage_twoLists = PageTemplateFile( 'two_lists', _wwwdir )
00341 
00342     manage_options=( ( { 'label'  : 'Plugins'
00343                        , 'action' : 'manage_plugins'
00344                      # , 'help'   : ( 'PluggableAuthService'
00345                      #              , 'plugins.stx')
00346                        }
00347                      , { 'label'  : 'Active'
00348                        , 'action' : 'manage_active'
00349                        }
00350                      )
00351                    + SimpleItem.manage_options
00352                    )
00353 
00354     if _HAS_GENERIC_SETUP:
00355         security.declareProtected( ManageUsers, 'manage_exportImportForm' )
00356         manage_exportImportForm = PageTemplateFile( 'export_import', _wwwdir )
00357 
00358         security.declareProtected( ManageUsers, 'getConfigAsXML' )
00359         def getConfigAsXML(self):
00360             """ Return XML representing the registry's configuration.
00361             """
00362             from exportimport import PluginRegistryExporter
00363             pre = PluginRegistryExporter(self).__of__(self)
00364             return pre.generateXML()
00365 
00366         security.declareProtected( ManageUsers, 'manage_exportImport' )
00367         def manage_exportImport(self, updated_xml, should_purge, RESPONSE):
00368             """ Parse XML and update the registry.
00369             """
00370             #XXX encoding?
00371             _updatePluginRegistry(self, updated_xml, should_purge)
00372             RESPONSE.redirect('%s/manage_exportImportForm'
00373                               '?manage_tabs_message=Registry+updated.'
00374                                 % self.absolute_url())
00375 
00376         security.declareProtected( ManageUsers, 'manage_FTPget' )
00377         def manage_FTPget(self, REQUEST, RESPONSE):
00378             """
00379             """
00380             return self.getConfigAsXML()
00381 
00382         security.declareProtected( ManageUsers, 'PUT' )
00383         def PUT(self, REQUEST, RESPONSE):
00384             """
00385             """
00386             xml = REQUEST['BODYFILE'].read()
00387             _updatePluginRegistry(self, xml, True)
00388 
00389         manage_options = ( manage_options[:2]
00390                          + ( { 'label' : 'Export / Import'
00391                              , 'action' : 'manage_exportImportForm'
00392                              },)
00393                          + manage_options[2:]
00394                          )
00395 
00396     #
00397     #   Helper methods
00398     #
00399     security.declarePrivate( '_getPlugins' )
00400     def _getPlugins( self, plugin_type ):
00401 
00402         parent = aq_parent( aq_inner( self ) )
00403 
00404         if plugin_type not in self._plugin_types:
00405             raise KeyError, plugin_type
00406 
00407         if self._plugins is None:
00408             self._plugins = PersistentMapping()
00409 
00410         return self._plugins.setdefault( plugin_type, () )
00411 
00412     security.declarePrivate( '_getInterfaceFromName' )
00413     def _getInterfaceFromName( self, plugin_type_name ):
00414 
00415         """ Convert the string name to an interface.
00416 
00417         o Raise KeyError is no such interface is known.
00418         """
00419         found = [ x[0] for x in self._plugin_type_info.items()
00420                                 if x[1][ 'id' ] == plugin_type_name ]
00421         if not found:
00422             raise KeyError, plugin_type_name
00423 
00424         if len( found ) > 1:
00425             raise KeyError, 'Waaa!:  %s' % plugin_type_name
00426 
00427         return found[ 0 ]
00428 
00429 InitializeClass( PluginRegistry )
00430 
00431 def _satisfies( plugin, iface ):
00432     checker = getattr(iface, 'providedBy', None)
00433     if checker is None: # BBB for Zope 2.7?
00434         checker = iface.isImplementedBy
00435 
00436     return checker(plugin)
00437 
00438 def emptyPluginRegistry( ignored ):
00439     """ Return empty registry, for filling from setup profile.
00440     """
00441     return PluginRegistry(())