|
|
||||||||||||||||||
|
|
||||||||||||||||||
![]() |
![]() |
Issue 9 - Revision 8 / February 7, 2005
|
|||
|
Improving WebDAV in Zope and Plone -Leveraging Standards to Improve the WebDAV experience... NOW! - - - - - - - - - - - - By Sidnei da Silva | September 20, 2004
New tools are continually being created to enable new features and faster development of the most various kinds of applications. Obviously, the main target here is the browser interaction. Plone has proven to be especially suited for this niche, being widely recognized as one of the best Open Source Content Management Systems out there. However, Content Management is not only about being able to control your content. The Web browser, though a universal tool that is available on the most varied platforms, enabling people to reach and control their content from anywhere, is not rich enough to match existing tools with years of acceptance and tight desktop integration. This is the domain of Document Management, which is increasingly converging with Content Management. The WebDAV protocol was created for the purpose of integrating Web content into desktop authoring environments. WebDAV stands for “Web-based Distributed Authoring and Versioning”. It is a set of extensions to the HTTP protocol which allows users to collaboratively edit and manage files on remote Web servers. WebDAV has been present in Zope since the early days as a supported way of interacting with content, along with FTP and XML-RPC, but it has been mostly ignored due to the above-mentioned reasons. Providing a reasonable WebDAV experience is not a Herculean task. However, it requires some preparation and thought. Care must be taken not to break backwards compatibility. All the contracts must be clear and predictable; moreover, the scope must be clear so that we don't get stranded in overengineering and endless discussions. Over the last couple of months, while working for Enfold Systems, I've developed a couple of tools to improve and provide better control over the process of creating and modifying content via WebDAV. In the following pages I will explain the goals of each of these tools and discuss how they can be used together to build a better WebDAV experience by employing existing standard technologies and libraries, instead of reinventing the wheel. 3C: Controlling Content CreationThe first place where control is desired when using WebDAV is having a consistent behavior when you upload a piece of content. What kind of resource should be created? What is the format? How should the content be extracted from the upload? Is the metadata available in the upload? For this purpose, a tool exists in CMF which decides what object should be created given an uploaded file. This tool is called “Content Type Registry” and consists of a series of “predicates” that are applied in sequence until one of them matches certain aspects of the upload request. When a match occurs, the “portal_type” associated with the matching predicate is used to create a new content object. This tool is available on stock CMF and Plone sites, and can be found at the root of the site under the “content_type_registry” id. Though the UI for controlling the predicates is not optimal (and, in fact, can be extremely confusing), a lot of power is hidden there, and with the right configuration it can save you a lot of sweat. Each predicate is composed of a configurable “rule” which maps to exactly one “portal_type”. By default, the available predicates that you can choose from are the following:
As you can see, these predicates can be very useful for simple cases, where you have an “opaque” piece of content being uploaded and your tools behave accordingly. However, one may want extra flexibility, such as having the ability to control the type of content being created based on some value inside the file being uploaded. This is especially true for XML files, where you may want to encode the content type to be created into a special tag, or even select a different content type based on the presence of a tag or not.
For such special needs, a new product has been created to provide an additional set of predicates. This product is called “CTRExtras” and provides the following new predicates:
Of the examples above, certainly the most interesting one is that for XML. This kind of flexibility is desired, indeed required, given the nature of XML itself: it is possible to express a piece of information in several different ways. Importing and ExportingThough many people come to Zope from other CMSs, or from no CMS at all, very little effort has been put into creating a standard way of bulk-loading existing content and pre-populating content objects from existing data. It's common practice to build one-off tools that only solve the customer's immediate problem. A similar problem arises when one has to export content from Zope to an external system, either for integration or for doing off-band publishing directly from Apache. The biggest block to enabling a structured approach to importing and exporting content has been the lack of an introspectable content definition. With the advent of Archetypes, this situation has improved considerably. Most projects are switching existing development to use Archetypes, and it's now uncommon to see a new project which is not based on Archetypes. Bearing this in mind, it is clear that having a pluggable import/export framework for Archetypes has a good chance of bridging the gap and defining the next standard for content import/export in Zope.
Archetypes has several layers of indirection for abstracting storage from presentation and for allowing for high flexibility and pluggability of new components. One of these layers is called “marshall”, and it's used mainly for handling the uploading and downloading of content through WebDAV and FTP. Out-of-the-box, Archetypes provides two Marshaller implementations:
Currently, Archetypes allows one Marshaller implementation to be used at a time and doesn't try to do any check to see if the file being uploaded complies with the Marshaller being used. For example, if you are using an RFC822Marshaller and upload an HTML file, it's very unlikely that something useful will happen. In fact, there's a high chance that the only thing you will get is an exception. In order to improve the use of this feature, the “Marshall” product has been developed. “Marshall” provides the following features.
The Marshaller Registry approach is quite similar to the “Content Type Registry”. Several predicates are configured, and then evaluated sequentially until the first one matches. When there's a match, a Marshaller is fetched and processing is delegated to it. In addition to the above-mentioned features, the Marshall product also provides two predicates. Each predicate by default has a “TALES Expression” that is evaluated to decide whether the predicate applies or not. The predicate may also be additionally configured for rules that may apply. The only thing required from the predicate is the implementation of the “IPredicate” interface. A couple of variables are defined, which are to be used by the TALES Expression:
The predicates available by default are:
During my short history of development in the Zope community, I've been constantly surprised by the attitude of most developers when they are faced with a request for developing new features. Their gut reaction, nearly 90% of the time, goes like this: “Nothing existing fits the job. Let's write something from scratch.”. In doing this, they usually choose non-standard ways of dealing with the problem. While this might solve the immediate problem and give the developer a warm feeling of inner satisfaction, in the long term it just yields a complex of gnarly code and tons of different tools that don't play well with each other. More than that, it ends up causing more pain down the road, when a person who didn't originally develop the system is recruited to provide maintenance for the system. As you can imagine, besides having to understand the gnarly code, the person also needs to figure out a non-standard format without any documentation: as a result he may end up himself rewriting large parts of the system from scratch before even trying to understand where the real problem is located. I had this issue in mind for a long time when, to my surprise, Paul Everitt came up with the idea of defining an XML-based format, if possible with “RelaxNG” validation, which could be used for importing and exporting content, specifically Archetypes-based content. He had a couple of requirements, such as being able to roundtrip content while keeping “UIDs” and “references” intact and being able to make non-UID-based references. The first suggestion was to make use of RDF, and though this initially seemed like a great idea, it quickly got dropped because of our lack of immediate knowledge and the fact that we would have to introduce yet another library dependency, which was not desired in the short term. The fact that we expect this to be available by default in the next major release of Plone is yet another reason not to add more dependencies. If you are familiar with RelaxNG or any other kind of XML validation in general, there's a reasonably complex issue involved here, just waiting to be uncovered. Archetypes schemas can arbitrarily define fields, and a field can have one of many different types. And it gets even more tricky: a field may be validated using several validators only available in the Python form, and which we cannot introspect or easily map into an XML schema form. Thus, the interim solution we've come up with was the following:
It's obvious that mapping such a complex entity as an Archetypes schema to RelaxNG is not a lossless conversion. However, extra care will be taken to make the loss as low as possible. At this moment, we have not yet started on the RelaxNG schema export for the registry. One of the ideas we have in mind for the RelaxNG registry is to use an extension of the format used by James Clark's nxml-mode for the feature known as Schema locating file. Deconstructing ATXMLThe ATXML RelaxNG is relatively simple, yet still powerful given the recursive nature of RelaxNG. We tried to map the most commonly used fields to the “Dublin Core Specification for XML”, as CMF by default provides a working subset of the Dublin Core set. For Archetypes references, we tried to be flexible and allow one to use 3 distinct kinds of references:
UID and path references are resolved directly at runtime, when the file is being processed. Metadata references are resolved by doing a Catalog query, and if there's exactly one match, the reference is made by using the object found. If zero matches or more than one match is found, an exception is raised, signaling the error. Looking at the schema definition you probably notice (if you have some basic knowledge of RelaxNG) that pretty much everything is optional. This is especially nice in case you want to make bit-sized updates using XML, such as updating only one field or a small set of fields without having to provide values for the whole schema. The possible elements have been split into 3 main groups:
When interacting with Zope exclusively through WebDAV, one may want to retrieve extra information, such as workflow state, permission settings, Dublin Core metadata, etc. By default, Zope doesn't make this information available through WebDAV. However, given the way WebDAV is implemented in Zope, especially PROPFIND requests, it was relatively simple for us to build a framework that simplifies exposing those features. When Zope's WebDAV implementation receives a PROPFIND query it looks for an object's “property sheets” (which are by default contained in a “propertysheets” attribute, which is an instance of “OFS.PropertySheets.DefaultPropertySheets”) to build a proper response. The property sheets implementation then computes a list of existing property sheets on the object, extending this list with a “DavProperties” instance, which is a “virtual” (in the sense that it's non-persistent) property sheet created at runtime. Based on this analysis, we decided that it would be trivial to patch this mechanism in order to provide additional “virtual” property sheets which would then be exposed through a PROPFIND query. To make this even more powerful, and to add some level of control as to how/when the properties are made available, a new tool named “property_set_registry” was created. The tool itself is nothing more than a container for “Property Set Predicates”, which is evaluated to build a list of “virtual property sheets” to be made available for a given object.
Each predicate has a permission, to be checked in the context of the target object, and a TALES expression. If both the permission and the TALES expression evaluate to True, then the predicate applies to the given object, and a list of “PropertySheet” instances is returned. In order to achieve maximum flexibility and a minimum set of dependencies, these features were made available in a standalone product called “PropertySets”. The PropertySets product provides only the basic framework and a dummy “PropertySetPredicate” as an example. It works with a bare-bones Zope installation. An additional product has been created for providing a working example of how to use the framework. It is called “CMFPropertySets” and offers the following features:
For our WebDAV project, we made some improvements to Greg Stein's davlib. Our improvements include the following features:
Let's go through a complete example showing Zope's behavior with a standard Plone site, after installation and configuration of the following products:
Most of the products that were shown in this article are already available in public CVS/SVN either as part of the “Collective” or “Archetypes” projects. Some of them are not yet available, but should be released “Real Soon Now”:). We encourage you to try these products for yourself, as time permits, and to report your experience to us. Note that eventually we plan to fold some or all of these products into Plone itself, provided that the proposed PLIPs are accepted.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ZopeMag is committed to bringing you the best in Zope Documentation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() |
Reproduction of material from any of ZopeMag's pages without prior written permission is strictly prohibited. Copyright 2003 - 2005 ZopeMag |
|