15. Zope Services

Some Zope objects are service objects. Service objects provide various kinds of support to your “domain-specific” content, logic, and presentation objects. They help solve fundamental problems that many others have experienced when writing applications in Zope.

15.1. Access Rule Services

Access Rules make it possible to cause an action to happen any time a user “traverses” a Folder in your Zope site. When a user’s browser submits a request for a URL to Zope which has a Folder’s name in it, the Folder is “looked up” by Zope during object publishing. That action (the lookup) is called traversal. Access Rules are arbitrary bits of code which effect the environment in some way during Folder traversal. They are easiest to explain by way of an example.

In your Zope site, create a Folder named “accessrule_test”. Inside the accessrule_test folder, create a Script (Python) object named ‘access_rule’ with two parameters: ‘container’ and ‘request’. Give the ‘access_rule’ Script (Python) the following body:

useragent = request.get('HTTP_USER_AGENT', '')
if useragent.find('Windows') != -1:
    request.set('OS', 'Windows')
elif useragent.find('Linux') != -1:
    request.set('OS', 'Linux')
else:
    request.set('OS', 'Non-Windows, Non-Linux')

This Script causes the traversal of the accessrule_test folder to cause a new variable named ‘OS’ to be entered into the REQUEST, which has a value of ‘Windows’, ‘Linux’, or ‘Non-Windows, Non-Linux’ depending on the user’s browser.

Save the ‘access_rule’ script and revisit the accessrule_test folder’s Contents view. Choose Set Access Rule from the add list. In the ‘Rule Id’ form field, type ‘access_rule’. Then click Set Rule. A confirmation screen appears claiming that “‘access_rule’ is now the Access Rule for this object”. Click “OK”. Notice that the icon for the ‘access_rule’ Script (Python) has changed, denoting that it is now the access rule for this Folder.

Create a page template named ‘test’ in the accessrule_test folder with the following text:

<html>
<body>
  <pre tal:content="context/REQUEST">request details</pre>
</body>
</html>

Save the ‘test’ page template and click its “View” tab. You will see a representation of all the variables that exist in the REQUEST. Note that in the other category, there is now a variable named “OS” with (depending on your browser platform) either ‘Windows’, ‘Linux’ or ‘Non-Linux, Non-Windows’).

Revisit the accessrule_test folder and again select Set Access Rule from the add list. Click the No Access Rule button. A confirmation screen will be displayed stating that the object now has no Access Rule.

Visit the ‘test’ script you created previously and click its View tab. You will notice that there is now no “OS” variable listed in the request because we’ve turned off the Access Rule capability for ‘access_rule’.

15.2. Temporary Storage Services

Temporary Folders are Zope folders that are used for storing objects temporarily. Temporary Folders acts almost exactly like a regular Folder with two significant differences:

  1. Everything contained in a Temporary Folder disappears when you restart Zope. (A Temporary Folder’s contents are stored in RAM).
  2. You cannot undo actions taken to objects stored a Temporary Folder.

By default there is a Temporary Folder in your root folder named temp_folder. You may notice that there is an object entitled, “Session Data Container” within temp_folder. This is an object used by Zope’s default sessioning system configuration. See the “Using Sessions” section later in this chapter for more information about sessions.

Temporary folders store their contents in RAM rather than in the Zope database. This makes them appropriate for storing small objects that receive lots of writes, such as session data. However, it’s a bad idea use temporary folders to store large objects because your computer can potentially run out of RAM as a result.

15.3. Caching Services

A cache is a temporary place to store information that you access frequently. The reason for using a cache is speed. Any kind of dynamic content, like a a Script (Python), must be evaluated each time it is called. For simple pages or quick scripts, this is usually not a problem. For very complex scripts that do a lot of computation or call remote servers, accessing that page or script could take more than a trivial amount of time. Scripts can get this complex, especially if you use lots of looping (such as the Python ‘for’ loop) or if you call lots of scripts, that in turn call lots of scripts, and so on. Computations that take a lot of time are said to be expensive.

A cache can add a lot of speed to your site by calling an expensive page or script once and storing the result of that call so that it can be reused. The very first person to call that page will get the usual “slow” response time, but then once the value of the computation is stored in the cache, all subsequent users to call that page will see a very quick response time because they are getting the cached copy of the result and not actually going through the same expensive computation the first user went through.

To give you an idea of how caches can improve your site speed, imagine that you are creating www.zopezoo.org, and that the very first page of your site is very complex. Let’s suppose this page has complex headers, footers, queries several different database tables, and calls several special scripts that parse the results of the database queries in complex ways. Every time a user comes to www.zopezoo.org, Zope must render this very complex page. For the purposes of demonstration, let’s suppose this complex page takes one-half of a second, or 500 milliseconds, to compute.

Given that it takes a half of a second to render this fictional complex main page, your machine can only really serve 120 hits per minute. In reality, this number would probably be even lower than that, because Zope has to do other things in addition to just serving up this main page. Now, imagine that you set this page up to be cached. Since none of the expensive computation needs to be done to show the cached copy of the page, many more users could see the main page. If it takes, for example, 10 milliseconds to show a cached page, then this page is being served 50 times faster to your website visitors. The actual performance of the cache and Zope depends a lot on your computer and your application, but this example gives you an idea of how caching can speed up your website quite a bit. There are some disadvantages to caching however:

Cache lifetime
If pages are cached for a long time, they may not reflect the most current information on your site. If you have information that changes very quickly, caching may hide the new information from your users because the cached copy contains the old information. How long a result remains cached is called the cache lifetime of the information.
Personal information
Many web pages may be personalized for one particular user. Obviously, caching this information and showing it to another user would be bad due to privacy concerns, and because the other user would not be getting information about them, they’d be getting it about someone else. For this reason, caching is often never used for personalized information.

Zope allows you to get around these problems by setting up a cache policy. The cache policy allows you to control how content gets cached. Cache policies are controlled by Cache Manager objects.

15.3.1. Adding a Cache Manager

Cache managers can be added just like any other Zope object. Currently Zope comes with two kinds of cache managers:

HTTP Accelerated Cache Manager
An HTTP Accelerated Cache Manager allows you to control an HTTP cache server that is external to Zope, for example, Squid. HTTP Accelerated Cache Managers do not do the caching themselves, but rather set special HTTP headers that tell an external cache server what to cache. Setting up an external caching server like Squid is beyond the scope of this book, see the Squid site for more details.
(RAM) Cache Manager
A RAM Cache Manager is a Zope cache manager that caches the content of objects in your computer memory. This makes it very fast, but also causes Zope to consume more of your computer’s memory. A RAM Cache Manager does not require any external resources like a Squid server, to work.

For the purposes of this example, create a RAM Cache Manager in the root folder called CacheManager. This is going to be the cache manager object for your whole site.

Now, you can click on CacheManager and see its configuration screen. There are a number of elements on this screen:

Title
The title of the cache manager. This is optional.
REQUEST variables
This information is used to store the cached copy of a page. This is an advanced feature, for now, you can leave this set to just “AUTHENTICATED_USER”.
Threshold Entries
The number of objects the cache manager will cache at one time.
Cleanup Interval
The lifetime of cached results.

For now, leave all of these entries as is, they are good, reasonable defaults. That’s all there is to setting up a cache manager!

There are a couple more views on a cache manager that you may find useful. The first is the Statistics view. This view shows you the number of cache “hits” and “misses” to tell you how effective your caching is.

There is also an Associate view that allows you to associate a specific type or types of Zope objects with a particular cache manager. For example, you may only want your cache manager to cache Scripts. You can change these settings on the Associate view.

At this point, nothing is cached yet, you have just created a cache manager. The next section explains how you can cache the contents of actual documents.

15.3.2. Caching an Object

Caching any sort of cacheable object is fairly straightforward. First, before you can cache an object you must have a cache manager like the one you created in the previous section.

To cache a page, create a new page template object in the root folder called Weather. This object will contain some weather information. For example, let’s say it contains:

<html>
<body>

  <p>Yesterday it rained.</p>

</body>
</html>

Now, click on the Weather page template and click on its Cache view. This view lets you associate this page with a cache manager. If you pull down the select box at the top of the view, you’ll see the cache manager you created in the previous section, CacheManager. Select this as the cache manager for Weather.

Now, whenever anyone visits the Weather page, they will get the cached copy instead. For a page as trivial as our Weather example, this is not much of a benefit. But imagine for a moment that Weather contained some database queries. For example:

<html>
<body>

  <p>
    Yesterday's weather was
    <tal:yesterday tal:replace="context/yesterdayQuery" />
  </p>

  <p>
    The current temperature is
    <tal:current tal:replace="context/currentTempQuery" />
  </p>

</body>
</html>

Let’s suppose that yesterdayQuery and currentTempQuery are SQL Methods that query a database for yesterdays forecast and the current temperature, respectively (for more information on SQL Methods, see the chapter entitled Relational Database Connectivity.) Let’s also suppose that the information in the database only changes once every hour.

Now, without caching, the Weather document would query the database every time it was viewed. If the Weather document was viewed hundreds of times in an hour, then all of those hundreds of queries would always contain the same information.

If you specify that the page should be cached, however, then the page will only make the query when the cache expires. The default cache time is 300 seconds (5 minutes), so setting this page up to be cached will save you 91% of your database queries by doing them only one twelfth as often. There is a trade-off with this method, there is a chance that the data may be five minutes out of date, but this is usually an acceptable compromise.

15.4. Outbound Mail Services

Zope comes with an object that is used to send outbound e-mail, usually in conjunction with a Script (Python).

Mailhosts can be used Python to send an email message over the Internet. They are useful as ‘gateways’ out to the world. Each mailhost object is associated with one mail server, for example, you can associate a mailhost object with ‘yourmail.yourdomain.com’, which would be your outbound SMTP mail server. Once you associate a server with a mailhost object, the mailhost object will always use that server to send mail.

To create a mailhost object select MailHost from the add list. You can see that the default id is “MailHost” and the default SMTP server and port are “localhost” and “25”. make sure that either your localhost machine is running a mail server, or change “localhost” to be the name of your outgoing SMTP server.

Now you can use the new MailHost object from a Script.

15.5. Error Logging Services

The Site Error Log object, typically accessible in the Zope root under the name ‘error_log’, provides debugging and error logging information in real-time. When your site encounters an error, it will be logged in the Site Error Log, allowing you to review (and hopefully fix!) the error.

Options settable on a Site Error Log instance include:

Number of exceptions to keep
keep 20 exceptions by default, rotating “old” exceptions out when more than 20 are stored. Set this to a higher or lower number as you like.
Copy exceptions to the event log
If this option is selected, the site error log object will copy the text of exceptions that it receives to the “event log” facility, which is typically controlled by the ‘EVENT_LOG_FILE’ environment variable. For more information about this environment variable, see the chapter entitled Installing and Starting Zope.

15.6. Virtual Hosting Services

For detailed information about using virtual hosting services in Zope, see the chapter entitled Virtual Hosting Services.

15.7. Searching and Indexing Services

For detailed information about using searching and indexing services in Zope to index and search a collection of documents, see the chapter entitled Searching and Categorizing Content.

15.8. Sessioning Services

For detailed information about using Zope’s “sessioning” services to “keep state” between HTTP requests for anonymous users, see the chapter entitled Sessions.