ZopeMag's mascot the ZOPE fish


Article Finder
People
Issue 4 - Revision 9  /   July 9, 2003 


 
  ZopeMag Links:
Latest Issue
Credits
Issue 10
Issue 09
Issue 08
Issue 07
Issue 06
Issue 05
Issue 04
Issue 03
Issue 02
Issue 01
 
 
Downloads
     
  Letter from the Editor:
   Issue 4

Interviews:
Each issue we interview important people in the Zope world.

 Lalo Martins

Articles:
Throughout the quarter we cover topics of interest to Zope developers, designers, and users.

  Intro to Zope 3 Part II

  Working with My Media Manager

  Transactions by example: Part II

  Open Page Templates

  Python Scripts

  Building a New UI For Zope 3 Part II

Product Review:
Too many Products, too little time? ZopeMag keeps you up-to-date which Zope Products are worthwhile downloading.

  icoya
  Easy Publisher
  ZopeTestCase
  CPS
 
 
Downloads
     
  URLs / Download
Products we talk about in this issues Articles and Reviews

  icoya
  Easy Publisher
  CPS
  ZopeTestCase
 
     

Illustration by Brendan Davis
tutorial
Introduction to Zope 3

Introduction to Zope 3
- Part II
- - - - - - - - - - - -

By Steve Alexander | April 1, 2003

print

This is the second of two parts. Click here for the first article.

ZClasses and Zope 3

ZClasses in Zope 2 are great for running up a quick prototype of an idea. Many Zope programmers, and Web designers who dabble in programming just to get the job done, first got into programmig Zope through ZClasses.

However, they are very hard to maintain and become very complex if you start to use inheritance or other complex associations between ZClasses. It is not really possible to turn an application based on ZClasses into a Product written only in Python because the machinery that makes ZClasses work is so very specialised. In addition, the range of types of properties that are available for use in ZClass PropertySheets is very limited.

In Zope 3, we have an opportunity to change this. On the one hand, we don't want to lose the benefits of an "easy start". On the other, we don't want to have the complexity and "dead-end-can't-move-to-Python" nature of ZClasses.

I'm going to describe a "fantasy" situation where the goal is to create a simple "contacts management" application in Zope 3, without writing any Python code. This is the kind of thing that will replace what people use ZClasses for today.

The reason I call it a "fantasy" is because the mechanisms for this don't all exist in Zope 3X right now. But, I am confident that most of them will before a beta release.

Fantasy scenario

Say you have a bunch of your friends' names, addresses, email addresses and birthdays that you want to record as objects in Zope. So, you open your browser in the Zope 3 management interface, and click on "make a new managed schema".

You see a palette of the kinds of fields you can add. You drag-and-drop into a form on the screen a TextLine for the name, an EmailTextLine for the email address, a TextField for the address and a DateField for the birthday. You can change the names of the fields, give them meaningful titles, for when they are used to automatically generate HTML forms for editing objects using a browser, and add text for on-line help for each of them, if you like.

If you need a kind of field that isn't available, such as an Image field, with a few clicks you can install a software package that contains extra fields that another Zope developer has written.

You decide to name your new managed schema "Friend".

As soon as you've saved your managed schema, you can start adding "Friend" objects to folders in the management interface, just as you can add DTML Pages and Files and Folders. The add and edit forms get automatically generated with validating form-widgets based on the fields you chose when creating the "Friend" schema. You can override these if you like, but perhaps the defaults are fine for now.

All of the objects that you add are indexed. If you go back to where you defined the managed schema, you can get to a list of links to the URLs for each "Friend" instance that has been added.

You can alter the schema at any time, adding or removing or renaming or rearranging the fields, and the objects you have created will continue working as you'd expect. You can have all of the objects updated at once, or if there are lots of them you might want to have them only updated when they are edited anyway. This is possible because the managed schema keeps track of all the changes you make to the schema, as well as what is required to upgrade the data in objects between different revisions of the schema.

You can make your "Friend" objects work with the rest of Zope by providing adapters and views. For example, you can create a page that presents a "Friend" object as the page of an address book. You can use the Relationships service in a page that allows you to record the relationships that exist between different friends in real life, and show these as links in your browser.

When you've added a lot of "Friend" objects to the system, you might want to have them searchable. You can configure an adapter to say what important text you'd want to search among your Friends for: name, address, description... Zope objects can have "Dublin core annotations", so you could use these to record a "description" for each "Friend", without adding a new field for that.

For more about Dublin Core metadata click here. http://dublincore.org

You can set up a TextIndex to receive ObjectAdded and ObjectChanged events whenever someone adds or edits a "Friend" object. You can use the Query Service to search in the text index, and present the results in batches, sorted by relevance to the search terms that were entered.

It will be possible to do all of this without writing any Python code or any page templates or DTML - just by clicking around the Zope 3 management interface.

If you want to do more complex things with your "Friend" objects, you can convert the managed schema into a regular Python module containing an interface and a couple of classes.

Searching

The easiest way of making a site searchable in Zope 2 is to add a ZCatalog, and make sure all of your classes include CatalogPathAware in their bases, and have the right calls to re-index when they change.

If you want to allow a simple textual-content search then your classes need to have a principiaSearchSource method that returns a string containing all of the text that you might want to search for in an object. (principiaSearcSource is a Zope 2 "interface" of sorts: an object that has this method is saying "here is the relevant searchable text for this object.)

In Zope 3, things are somewhat similar, but broken up into separate components. Instead of ZCatalog, there is a QueryService, and various indexes and query-processors that you can plug in to make the queries that you need.

You can make any kind of object searchable without adding an extra method to it. You provide an ISearchableText adapter that knows how to convert a particular kind of object into a bunch of interesting text. This is a good thing because it means you can make someone else's product searchable without having to edit the code of their product.

Here's what the SearchableText adapter for a File looks like:

    class SearchableText:
        implements(ISearchableText)

        def __init__(self, file):
            self.file = file

        def getSearchableText(self):
            if self.file.contentType == "text/plain":
                return [unicode(self.file.data)]
            else:
                return None

If the file has the content-type 'text/plain', then we use its text. Otherwise, we return None to say that we have no searchable text for this file. If you don't like this policy for getting searchable text from a file – perhaps you have a way of getting searchable text from a Microsoft Word file into a form usable from Python code – then you can override this adapter with one of your own. This just takes a bit of XML in a configuration file. For example, here's the XML that configures the standard searchable text adapter for a file.

    <adapter
        factory="zope.app.content.file.SearchableText"
        provides="zope.app.interfaces.index.text.ISearchableText"
        for="zope.app.interfaces.content.file.IReadFile"
        />

To provide your own, just add some XML that looks like this, but has the name of your class in the 'factory' attribute.

Unicode and internationalisation

Zope 3 is built using unicode for textual string data. Pages are (by default) rendered in the UTF-8 encoding. The plan is that before the final release, all text will be localisable.

Security

In Zope 2 you protect the methods of a class by a combination of adding or removing docstrings, using an underscore at the start of the method name, and using the security.declareProtected('Permission name', 'method_name') declarative security system.

This works, and is good for many purposes. But it has a few problems:

  • It is confusing to have the presence or absence of docstrings influence whether you can access a method.
  • It is sometimes annoying that you cannot call a method the name of which happens to start with an underscore from a page template or a DTML method.

    In Zope 2, you protect methods using a confusing variety of mechanisms: security assertions in the class, the presence or absense of a docstring, whether the name of the method begins with an underscore. This is unfortunate because docstrings are meant to help you document methods, and shouldn't affect the security of those methods. Encoding security information in the name of a thing is a bad idea because although your security needs might change, you would still want to keep the same name.

    For Zope 3, we only use security assertions (which are made in XML files rather than in the class itself) to protect a method or attribute. So, there's nothing stopping you from using a docstring where you want to use a docstring, and using a name starting with an underscore where you want to use such a name. The same goes for the special treatment that names starting with 'manage_' get in Zope 2. There is no such special treatment in Zope 3.

  • The declarative security statements make it more difficult to read and maintain the code. They are just another thing that stops Zope 2 code from looking and working like normal Python code.

In Zope 3, the permissions needed to access a class's methods are specified in XML files. Here's an example of the security declarations for a ZPT page:

<content class="zope.app.content.zpt.ZPTPage">
  <factory
      id="ZPTPage"
      permission="zope.ManageContent"
      title="ZPT Page"
      description="A simple, content-based Page Template" />

  <require
      permission="zope.View"
      attributes="__call__ macros" />

  <require
      permission="zope.ManageContent"
      interface="zope.app.interfaces.content.zpt.IZPTPage"
      set_attributes="source expand" />

  <require
      permission="zope.View"
      interface="zope.app.interfaces.content.zpt.IRenderZPTPage" />

</content>

Mostly, the security is declared in terms of different interfaces. So anyone with the zope.View permission can render a ZPT page as described in the IRenderZPTPage interface. They can also use the '__call__' method and the 'macros' attribute. That's right: 'macros' is an attribute. The Zope 3 security system works the same whether you're protecting methods or attributes or Python 2.2 properties. If you have the zope.ManageContent permission, you can read and call the attributes and methods in IZPTPage, and also set the attributes 'source' and 'expand'. You need the zope.ManageContent permission to create a new ZPT page, as declared in the 'factory' XML element at the top of the example.

However, none of this influences what names you can get to directly using a Web browser. If you want this, you'll have to look elsewhere, where the "views" on ZPT pages are declared. There are different views for Web-browsers and for FTP clients and for XMLRPC clients. This is a good thing. You don't want people browsing to:

http://example.com/folder/zptpage/macros

So, how does all this new stuff work?

In Zope 2, security assertions add special attributes to classes. While processing URLs and paths, Zope looks for these special attributes on the objects it traverses. The value of a special attribute says things about what role a user must have to do a particular thing with that object. This whole process can become pretty slow.

For Zope3, rather than adding special attributes to objects, the objects are "wrapped" in a security proxy that guards access to the object's attributes and methods. You can hardly tell the wrapper is there. The objects work pretty much the same as before, unless you try to access an attribute that is forbidden to you, in which case either an "Unauthorized" error will be raised offering you the chance to authenticate, or a "Forbidden" error will be raised if authentication would not help. The wrappers are written in C, so they work speedily. It takes an explicit call to a special function to remove the wrapper.

The security wrappers are added for you automatically by the Zope framework, so you don't need to worry about securely wrapping things before returning them from your code.

One consequence of this is that you can safely return mutable data (such as a list or dict) from a method, and be sure that it will not be changed by other code.

For example, in Zope2, the PropertyManager.propertyMap() method has to make a copy of the property definitions dictionary, and then return it. Otherwise, a program could deliberately or inadvertently change the property manager's internal data.

In Zope 3, the security proxy allows access to a dictionary only for reading attributes, and for calling methods that won't change the data. So it's easy for the Zope 3 equivalent of a PropertyManager to return a dictionary.

Such coding becomes much more straightforward, and it is much less likely that this kind of security error will be made.

Conclusion

I hope this has given you some sense of what Zope 3 will be like. Of course there will be many other changes than the ones described here but I've selected a few of the more interesting ones. Those who want to get more of a feel for the new version can download the current alpha version of Zope 3X from:

http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/Downloads

but don't forget that this is being written without an eye for backwards compatibility with Zope 2.x.


Steve Alexander:

Steve Alexander was born in England in 1974. He holds an honours degree in Computer Science and Software Engineering, and is a member of the IEE.

Steve runs a Zope consulting company that produces software for human resource departments. He is a contributor to the ongoing Zope 3 project, and has sprinted in Fredericksburg, Reading, Rotterdam, and Vilnius. Steve currently works from Vilnius, Lithuania, working alongside CodeWorks.


shim
shim  ZopeMag is committed to bringing you the best in Zope Documentation. shim
shim


Home   Subscribe   FAQ   Contact   Write for us   Privacy Policy   Weekly News   PyZine   opensourcexperts.com  

Reproduction of material from any of ZopeMag's pages without prior written permission is strictly prohibited. Copyright 2003 - 2005 ZopeMag Zope/Plone hosting by Nidelven IT