Reuven gives a whirlwind tour of the open-source Zope application server, beginning with an exploration of Zope as a web development platform.
No matter what language and operating system you use, web development typically means working with HTML files, graphic files, standalone programs, hybrid HTML/code templates and a connection to a relational database. Experienced developers can move easily from Perl to PHP to ASP because the concepts translate from one language to another with only minor variations. This convergence of paradigms has been convenient for developers, at the cost of complacency and laziness in the web development community.
Luckily, the open-source Zope application server is there to shake us from our complacency and open our eyes to new ways in which we can develop web applications. Zope, written and supported by Zope Corporation (formerly Digital Creations), changes everything that you ever knew about web development. You still can create dynamically generated content and work with relational databases, but Zope does so in very different ways from every other application server on the market.
This month, we begin to explore Zope as a web development platform. Along the way, I hope it becomes obvious that while Zope is different from other environments, its elegance and power make it a strong contender for open-source enthusiasts.
Part of the difficulty in understanding Zope is that it's actually several things at once. Simply put, Zope provides you with everything you need to create web applications. Installing Zope gives you a simple HTTP, FTP and Web-DAV server (known as the ZServer), an object database (known as ZODB) and a framework for creating server-side web applications.
Most of Zope is written in Python, which means that it is ported across platforms easily. And while it makes sense that a program written in Perl, Python or Java can run equally on Linux and Windows easily, it is still unusual for a prominent open-source system to run on Windows.
A typical web site has a mix of static HTML files, templates and graphic files. When the HTTP server receives a request, the server determines what kind of file was requested (by looking at the file's extension, location and MIME type), executes any necessary code inside the file and returns an HTTP response.
In Zope, nothing is stored on the filesystem. Rather, all site content and programs are stored inside of the ZODB object database. (The database itself typically is stored as a large disk file, which can be backed up or copied to backup Zope servers.)
To create a simple HTML file, you will need to create a “file” object in ZODB. To display an image on the web site, you will need to create an image object in ZODB. And to execute a piece of code when a certain URL is invoked, you must store the code in ZODB.
Luckily, storing and retrieving items in ZODB is quite easy. Zope takes care of most of this for you, allowing you to set high-level parameters at installation time. Moreover, Zope is designed so that it can be controlled completely via one web browser. You can use one of Zope's web-based tools, which makes it possible to create, edit and administer a web site using nothing more than your web browser. So you can create, modify or delete any content on the site (HTML, images or directories) using your browser.
If you prefer to edit text (and code) in Emacs rather than in a web text area, the ZServer supports FTP, displaying the objects in ZODB as if they were in a filesystem hierarchy. If you (and the nontechnical staff that you trained) previously were using FTP to transfer files to and from your web server, ZServer's FTP implementation will allow you to continue along that path almost seamlessly.
For all of its complexity, Zope is surprisingly easy to install. You will need to download the latest version from www.zope.org (see Resources). After you choose the version that you want to download, switch into your Zope directory (typically /usr/local/zope/, but anything will do), and unpack the Zope file:
mkdir /usr/local/zope cd /usr/local/zope tar zxvvf /downloads/Zope-2.4.3-linux2-x86.tgz
Opening up the Zope archive reveals a number of directories, including:
bin, where the Zope startup and shutdown scripts are located.
doc, where the complete Zope documentation is kept.
lib, where Python and all of the various Zope applications (known as products) are kept.
ZServer, which contains the classes necessary for the ZServer.
utilities, which contains several Zope-related utilities.
Before you can start Zope for the first time, you must install it with the install script. Only run this script after you have placed the Zope files in their final location, since install uses the current directory name to set several global configuration values.
After you have finished installing Zope, you can start it up by running the start script in the main Zope directory. By default, this script starts Zope's HTTP server on port 8080 (with an FTP server running on another port). You can change these values with a command-line switch; a full list is available by typing start -help.
While Zope is written largely in Python, Python does not need to be installed on your system. Zope comes with its own copy of Python, which it uses instead of whatever is on the operating system. This decreases the chances for version problems and errors. As of this writing, Zope uses Python 2.1 (the latest stable version), but Python 2.2 should be coming out in the near future. It will be interesting to see when Zope adopts it.
The install script not only sets up the initial Zope configuration, but also creates a hard-to-guess password for the system's “admin” user. We will need this password in just a few minutes, so be sure to write it down.
Now that we have started Zope, how do we use it? Well, the first and most important step is to fire up our web browser and point it to our computer, giving it the URL http://localhost:8080/. This displays some initial Zope information, including pointers to documentation and web sites.
Let's leave this introductory screen behind, moving instead to the main Zope management interface at http://localhost:8080/manage. You will be prompted to enter the username and password for a site manager; use the admin user and the password that the install script printed out when you first installed Zope.
Once you have entered the correct password, your browser window will be divided into two vertical frames: the left-hand side displays the hierarchy of your Zope server, while the right-hand side displays the details of the object you are currently viewing.
It's easy to understand what happens when you ask an Apache server for the document /foo/bar. Apache looks for a file named bar in the foo directory underneath its document root. If such a file exists, then Apache reads it from disk and returns its content in an HTTP response. If the file is a CGI program, then it executes the program and returns its output in an HTTP response. And if the file does not exist, Apache returns an error message to the user's browser.
Zope interprets URLs quite differently; the URL /foo/bar is interpreted as a request for Zope to invoke a display method on the bar object inside of the foo object. If either foo or bar does not exist, then Zope will return an error message indicating that no such object can be found in ZODB.
If we always had to worry about creating objects and writing display methods, then Zope would be a high-powered toy for programmers. Luckily for us, Zope lets us almost pretend that ZODB is a hierarchical filesystem into which we are placing our HTML files and graphics.
For example, we can create a simple HTML file using nothing more than our web browser. While inside of Zope's root folder (to which you can always return by clicking in the upper left-hand side of the browser's left frame), create a new document by choosing DTML Document from the “Select type to add...” selection list in the top right-hand corner. (As we will soon see, DTML—Document Template Markup Language—is Zope's superset of HTML; Zope almost always refers to DTML documents rather than HTML documents.)
Your web browser should now display a short HTML form with three elements:
The id text field. Every object in Zope has an ID, and IDs must be unique within a folder. IDs are analogous to filenames on a disk, and they are used to identify objects within a URL. In the URL /foo/bar, foo is the ID of a folder object, while bar is the ID of an object within that folder. Zope documents traditionally don't have suffixes (e.g., .html and .gif); because the system knows what type of object is associated with each ID, such a suffix would be redundant.
The title text field. The object's ID appears in URLs, but the object's title appears in all of the internal Zope management screens. (The object's title has nothing to do with the HTML <title> tag, which you still will have to create.)
The file element allows you to upload a file from your local computer using HTTP uploads. This means that you can create a DTML file on your local computer and upload it to Zope when you are ready for testing.
For the purposes of this example, we will enter an ID of testdoc, and a title of “Test document”. While we simply could add this document to ZODB, that would leave it empty. Thus, we will click on the “Add and edit” button, which gives us a text area with some default content:
<dtml-var standard_html_header> <h2><dtml-var title_or_id></h2> <p> This is the <dtml-var id> Document. </p> <dtml-var standard_html_footer>
You can edit the contents however you want within this text area. When you have finished, click on the save changes button at the bottom of the screen. This button brings you back to the editing window but adds a reminder indicating when the document was last modified.
Our DTML document looks very much like HTML, except that it includes several tags that begin with <dtml-var>. DTML is actually a programming language that lets you do all sorts of things, but it is probably easiest (and best) to think of it as a very strong server-side include mechanism. As demonstrated in this sample document, <dtml-var> lets you insert dynamic values into the current document. Thus <dtml-var standard_html_header> inserts the contents of the object with the ID of standard_html_header, while <dtml-var id> inserts the ID of the current document. As you can imagine, <dtml-var title_or_id> displays either the title or the ID, depending on whether a title has been defined.
When Zope encounters the expression <dtml-var standard_html_header>, it looks in the current folder for an object with the ID standard_html_header. If such an object exists, then the <dtml-var> tag is replaced with the object's viewable contents. If no such object exists, then Zope repeats its search in the enclosing folder. In this way, Zope works its way up the entire hierarchy until it reaches the root folder.
This means that automatically inserted headers and footers depend not only on our <dtml-var> tags, but also on the location of our DTML document. The notion that an object's location in the object hierarchy affects its output is known as acquisition in the Zope world, and it is both important and useful. Using acquisition, you can have a different set of headers and footers for each folder. Moving a document from one folder to another changes the search path that Zope uses when looking for headers, footers and other objects. The behavior of an object in Zope thus depends not only on its definition, but also on its location in the object hierarchy. For this reason, acquisition is sometimes explained as analogous to the “nature vs. nurture” debate in biology: an object's definition can be seen as “nature”, while its location in the object hierarchy can be seen as “nurture”.
To view the current contents of the document, click on the view tab at the top of the frame. You will see the document's contents exactly as a user would want. To edit the document once again, I find it easiest to click on the “Root folder” link in the top-left corner, select the testdoc object and then edit things once more using the text area.
If you make a mistake while editing a DTML document, you will be happy to know that Zope provides infinite undo. Click on the undo tab on the top right of the DTML editing screen, and select the version to which you want to return. Infinite undo is one of my favorite features in Zope, not only because it allows me to undo my mistakes, but because it's so easily accessible to nonprogrammers, and it works with any kind of object on the system.
There are a number of DTML tags, each of which begins with dtml-. Most DTML tags take one or more parameters, where each parameter allows it to work in a slightly different way. For example, we can modify our test document to include a simple use of <dtml-var expr>:
The value of our expr in the above code is a simple Python expression. Zope evaluates the expression and replaces the dtml-var tag with the result of that evaluation. We also can try something more interesting than simple addition. For example, we can use the capitalize method in the string module (automatically imported into Zope) by naming it in the expr attribute:
<p><dtml-var expr="_.string.capitalize('abc')"></p>Notice how we cannot invoke string.capitalize(), but must rather invoke _.string.capitalize().
While DTML allows you to use the string module in this way, you may never have to invoke it directly because so many useful string functions are built into DTML.
DTML was made for designers and other nonprogrammers to be able to create their own dynamic content without being stuck with the poor syntax and documentation of server-side includes. DTML is not as easy for nonprogrammers to learn as some of us might think, but it is far easier than teaching them a full-fledged programming language. And the fact that Zope performs some error checking when saving the DTML document helps to avoid some of the issues associated with runtime languages.
This month, we took a whirlwind tour of several of Zope's features, including through-the-web editing, the management interface, acquisition and simple DTML documents. Next month, we will look at Zope products—how to download and install them, and then how to write our own.