Bluebream uses the Zope Component Architecture, which provides you with registries of components, such as adapters or utilities. You can create two types of registries: global and local. The global registry is unique, created automatically, and populated with all the registrations done in the ZCML files. The local registries are persistent and typically live in the ZODB database, in what is called a local site manager. Local registries allow you to override or create component registrations in the object hierarchy, in a contextuel manner.
This document explains how to create a local site manager. To try the examples given here, you can create a project as explained in the Getting Started document. Here are the commands to create a sample project.:
$ easy_install bluebream $ paster create -t bluebream sampleproject python_package=mycompany.main $ cd sampleproject $ python bootstrap.py $ ./bin/buildout
To add a local site manager to the sample application, you need to add one line of code to AddSampleApplication class in src/mycompany/main/welcome/views.py file, inside createAndAdd method just before the last line:
Be sure to add the following import at the top of the file:
from zope.site import LocalSiteManager
So, the last three lines will look like this:
self.context[name] = app app.setSiteManager(LocalSiteManager(app)) self.request.response.redirect(name)
That’s it. Now, each application added using this form will be a “site”. But what does it mean?
A Site is a persistent object used to provide custom component setups for a part of your application or the whole web site. For this purpose, it contains a Site Manager, which is:
Imagine this hierarchy in the ZODB:
root---------FIRST | +---(++etc++site)---RootCookieManager | +-----------------app-------------SECOND | +---(++etc++site)---AppCookieManager
++etc++site means Local Site Manager itself. Thus, root and app are Sites. Let’s make RootCookieManager and AppCookieManager to be utilities registered in their Site Managers as utilities providing interface zope.session.interfaces.IClientIdManager and with an empty name.
Let’s query unnamed utility provided interface zope.session.interfaces.IClientIdManager:
It was local site managers and local (persistent) components. There are yet another sort of registry - global component registry (global site manager), which you have use for registering non-persistent components. We will not explain it in this document.
When do you need local utilities? Here are some reasons to create a local utility:
Which local utilities are commonly used? List of interfaces they provide:
In the add form above, you set the Site Manager directly in the form. But let’s separate this logic from the view. Events system is another edge of polyhedron of the Component Architecture used in BlueBream. Event caller and event handler do not know about each other and even do not require each other.
We don’t need to write a caller for this event, because it is done by the container itself. When you add an object into the container, it calls an event which provides interface zope.lifecycleevent.interfaces.IObjectAddedEvent.
Handlers in BlueBream (generally, in ZTK) are subscription adapter factories that don’t produce anything. This implies a lot of interesting possibilities, but we won’t consider them in this document. Just write it - it is a simple function (handler.py):from zope.site import LocalSiteManager def siteAdded(site, event): site.setSiteManager(LocalSiteManager(site, False)) sm = site.getSiteManager()
and register this function as a handler for events which provide interface IObjectAddedEvent (configure.zcml):<subscriber for="sample.welcome.interfaces.ISampleApplication zope.app.container.interfaces.IObjectAddedEvent" handler=".handler.siteAdded" />
As we showed above, “A Site is a persistent object used...” But in the terminology of the component architecture we don’t need to speak about objects, i.e. about implementations. It is sufficient to speak about interfaces which these objects do provide.
In this “language”, Site is an object which provides interface zope.component.interfaces.ISite. And it happens automatically after we set Local Site Manager. But to do this, we need an object which implements zope.component.interfaces.IPossibleSite. That is why you have used zope.site.folder.Folder container. Thus, there is a conversion:
IPossibleSite ---> ISite