You are on page 1of 3

How the system works


There are lots of design decisions that have been made to make this
project possible. Some of them are crucial to make the system work.

I will try to describe here how some parts of it work, like the
publisher, the traversal adapters and the xslt theme/pipeline.


We have a custom `server type`, which has a custom

PublicationRequestFactory. The `server type` is defined in
``snap/``, and the `request factory` is in

Why we did this?


Because we wanted to have a ZODB-less Zope 3 application, but we are

using Zope 3.1 so that's the only way to do it. In Zope 3.2 will be
possible to write this as a WSGI app and apparently there will be also
other ways to providing a custom PublicationRequestFactory, though I'm
not that sure on the latter.

What it does?

The request factory basically returns the ``root`` or ``application``

object equivalent to the ``application`` object in Zope 2. This is
done by (you guessed?) the ``getApplication`` method in the request

For LSTech we just return a dummy singleton object which has a marker
interface, and from there on Zope 3 uses traversal adapters to find
the next objects in the traversal path.

Another thing it does is to run the result of ``callObject``, which

(as you might have guessed) calls the published object pretty much the
same way it's done in Zope 2, by using ``mapply``. Note that in Zope 3
though, the published object is (almost?) always a ``view``.

So, all things keeping sane, ``callObject`` will receive a view, call
it and get some stream/string of content. If it smells like HTML or
XML, we run it through the pipeline, otherwise it's returned

The rest of the code in there is pretty much copied over from
``BrowserPublicationRequestFactory`` (?) just because we did want some
features from there but not all, and although Zope 3 uses adapters
everywhere, the publication part is not one of them.

Alright, if you got this far lets jump now to the next part of the
puzzle which is traversing objects.

For traversal we pretty much rely on the standard behaviour of Zope 3,
which is to lookup a ``ITraversable`` adapter, and sometimes a
``IPublishTraverse`` view depending on the way traversal happens. Yes,
it's more complicated than it should and we should kick Jim for that.

The theory is that if a traversal is being done by the publisher, then

there is a request, and a IPublishTraverse view is looked up, which is
just a multiadapter between the object and request. If you don't know
what that means don't be scared. It's non-trivial, really.

To simplify the matters a little, we registered a IPublishedTraverse

for all our objects which tries a ITraversable adapter first and then
tries to lookup a view, and if all fails, tries a
``resource``. Resources are usually CSS and images used in the skin.

Application Traversable

From the application object, the first thing we do is to see if the

name being looked for is one of the top-level 'Topics' on the site.

If that's the case, we do a XPath query on the ``map.xml`` file which

is generated by Entransit to see if a Topic or Location with that name

If a Topic or Location is found, a corresponding object is created and

some metadata is stitched on it by calling the ``metadata_setup``
function. More on that later.

Otherwise we delegate down to the Directory Traversable adapter.

Directory Traversable

This little beast now checks if the name being traversed is not a
attribute or item on the adapted object. If it is, then it returns

If a attribute/item is not found, then a lookup is done on the

filesystem. The path on the filesystem is computed from a prefix,
which is the snap/data directory path + the relative url being
traversed from the application root.

If the path exists and it's a directory, then a appropriate object is


Otherwise we first look for the path and return a Content object, or
look for path + '.data' and return a Metadata object.

If all fails, a NotFoundError is raised.

Once the full path has been traversed, the last item in the traversal
path will go through the IPublishTraverse and either a view or a

Metadata Setup
There's a function called `metadata_setup` that populates the objects
created by traversal. This function first reads the file created by
Entransit using xmlrpclib.loads then does a query on the ``cmf_meta``
table and stitches all those values into the object.

The last step then is to declare a marker interface on the object

based on the `portal_type` attribute that was populated from the
``cmf_meta`` table.

XSLT Pipeline

There is some magic going out there that probably Cameron understands
better than I. The basic idea is that you have a 'template' which is a
plain XML/XHTML file with the look and feel of the website.

On top of that a XSLT is applied which generates another XSLT (think

Escher), which is then applied to what Zope returns from

The 'template' file is in ``snap/browser/theme/index.xml``. It does

define a couple ``<div id="something">``. Then comes
``snap/browser/theme/rules.xsl`` which defines how the content from
Zope will be stitched into the template. For example::

<rule themeid="discussion-body"

The rule above basically says that whatever is inside a ``<div

id="discussion">`` tag in the content returned by Zope, will be
stitched into a ``<div id="discussion-body">`` tag in the
``index.xml`` template.

If you think that's complex, don't. It's actually pretty trivial but
your brain might not be wired to think that way.