## $Id: meta.py 7819 2012-03-08 22:28:46Z henrik $ ## ## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## """Grokkers for Kofa components. Stuff in here is mainly taken from grok.meta, with some modifications to provide a possibility to update catalogs in a running site. This is to solve the very common problem of already running sites for which the software changes and adds catalogs. These catalogs will not be automatically added in a running site. With the following Grokker and the upgrade helper class we can fire IObjectUpgradedEvents for any existing site and all catalogs registered will be really created. Please note that yet these catalogs are not filled automatically! That means the catalogs will exist but are empty in the beginning. We might solve this second problem by firing extra events like some ICatalogUpdatedEvent (which still do not exist) or similar. """ import grok import martian from grok import components from grok.meta import IndexesSetupSubscriber from martian.error import GrokError from zope import component from waeup.kofa.interfaces import IObjectUpgradeEvent class IndexesGrokker(martian.InstanceGrokker): """Grokker for Grok index bundles.""" martian.component(components.IndexesClass) def grok(self, name, factory, module_info, config, **kw): site = grok.site.bind().get(factory) context = grok.context.bind().get(factory, module_info.getModule()) catalog_name = grok.name.bind().get(factory) if site is None: raise GrokError("No site specified for grok.Indexes " "subclass in module %r. " "Use grok.site() to specify." % module_info.getModule(), factory) indexes = getattr(factory, '__grok_indexes__', None) if indexes is None: return False subscriber = KofaIndexesUpgradeSubscriber( catalog_name, indexes, context, module_info) subscribed = (site, IObjectUpgradeEvent) config.action( discriminator=None, callable=component.provideHandler, args=(subscriber, subscribed), ) return True class KofaIndexesUpgradeSubscriber(IndexesSetupSubscriber): """Helper that sets up indexes when their Grok site is upgraded. Each `grok.Indexes` class serves as an assertion that, whenever an instance of its `grok.site()` is upgraded, the given list of indexes should be generated if not already created as well. But a long period of time could elapse between when the application starts (and its indexes are grokked), and the moment, maybe days or weeks later, when a new instance of that `grok.Site` is created. Hence this `IndexesSetupSubscriber`: it can be instantiated at grokking time with the index information, and then registered with the Component Architecture as an event that should be fired later, whenever the right kind of `grok.Site` is instantiated. At that point its `__call__` method is kicked off and it makes sure the index catalogs get created properly. """ def __call__(self, site, event): site.logger.info('Create catalog `%s` if not installed yet.' % ( self.catalog_name,)) # make sure we have an intids self._createIntIds(site) # get the catalog catalog = self._createCatalog(site) # now install indexes for name, index in self.indexes.items(): try: site.logger.info('Create index `%s` in catalog.' % name) index.setup(catalog, name, self.context, self.module_info) site.logger.info('Index created.') except KeyError: #, DuplicationError: site.logger.info('Index `%s` already in catalog.' % name) pass site.logger.info('Catalog `%s` ready.' % self.catalog_name)