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. Publisher --------We have a custom `server type`, which has a custom PublicationRequestFactory. The `server type` is defined in ``snap/server.py``, and the `request factory` is in ``snap/publication.py``. 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 factory. 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 unmodified. 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. Traversal ---------

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 exists. 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 immediately. 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 returned. 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 resource. 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 ``callObject``. 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" contentxpath="/html:html/html:body//html:div[@id='discussion']/*"/> 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.