CHAPTER 10
Integrating Plone with Other Systems

Plone's nature is well-connected with the goal of managing web content through the Web and using proprietary (albeit open source) tools, such as the Python coding language and the ZODB object database. But Plone is more than this as well. If you investigate a bit, you'll discover that Python is an easy-to-learn, powerful tool with a complete set of extensions, enriching you with loads of extra possibilities. And Plone is Python. As well, Plone is Zope. And this opens to many other possibilities.

For instances, ZODB provides a nice storage layer for your content because it's so transparent and robust in its operation behind the curtain of Zope. And thanks to its roots in Python and Zope, Plone can go far beyond what you would expect from an application aiming at such an "easy" task as managing web content through the Web. In this chapter, we will delve into how to access Plone using methods different from the standard web user interface, as well as how to integrate Plone with other systems. First, we'll discuss how to link Plone with a file system, both through Plone's web interface and as a network share. Then we will make a foray into integrating a relational database in Plone, adopting classical Zope 2 techniques and using the SQLAlchemy library as a bridge. Next, we will figure out how to access Plone content without a web browser, using the WebDAV or FTP protocols; and, finally, we will take a look at Plone as a web service, glancing over the RSS, XML-RPC, and WSGI technologies.

Publishing the File System

Publishing folder content on the server file system requires a few steps, and this is because of security concerns. Of course, you could bypass the security issues by enabling Apache or an equivalent proxy web server to serve such folders directly, but every time a user wants to publish new folder content, a systems administrator will be needed to help.

The problem we want to solve here is, "How can a Plone user register a folder local to the server to be accessed as a normal Plone folder, but using its original files as objects, and all without asking a sys admin to lend a hand?" You might run into this use case in many circumstances, such as when you have a whole slew of documentation files and you would like them to be rapidly accessible through your intranet/extranet, giving access to them as you do for standard Plone folders.

You can provide this functionality within your Plone instance by extending it with some special products, like the one we suggest here: Reflecto. At the time of writing, Reflecto 2.0 is one of the most adopted solutions given by the Plone community to this special issue; it comes, in fact, after some other long-adopted products, such as LocalFS. You can find it on the Plone.org site, at http://plone.org/products/reflecto.

As stated by its official description, "Reflecto is a tool to incorporate part of the file system into a Plone site" as Plone content. Reflecto acts as a window for browsing the local file system and accessing the files in it as if they were Plone file objects. Using Reflecto, files in the mapped parts of the file system are indexed and searchable in Plone's catalog, can be copied and pasted, and can be renamed. They can be added from the file system or through Plone.

Let's now examine Reflecto more deeply. First, install Reflecto by unarchiving the downloaded package in your Products folder, or running your buildout script after having added Products.Reflecto to eggs in the buildout section, and to zcml in the instance section of your buildout.cfg file. You have seen these operations in detail in Chapter 9.

Start your local Zope service and create a new Plone site. Go to the Plone Control Panel and choose Add/Remove Products, and then select Reflecto from the list and click Install (if you have any doubt about this step, see the "Adding/Removing Products in Your Site" section of Chapter 4). At the end of this process, you should have a new content type named Reflector available in the Add New menu of your Plone folders.

A Reflector is a standard Plone object you can create in any Plone folder to open a window on the local file system. Just specify a title and a local file system folder path in the edit form of your Reflector object, and you will be able to navigate the contents of the folder corresponding to the path you give, subfolders included. You will also be able to rename, delete, and create new files using the Plone Contents tab, just as you would expect. As a note and invitation to read the Reflecto documentation, notice that files with file names that would clash with Plone's naming conventions will be ignored by Reflecto; for instance, Reflecto will not display files whose file name starts with @@, or contains a +.

Note Of course, the local file system has its own security machinery. For this reason, to access the local file system through Plone as expected, you need to give read/write permissions to the system user running the Zope service.

Reflecto is an easy and effective tool, but those files you can see in Plone using a Reflector object are not standard Plone objects in the ZODB database! If you choose the "Show live data" option in the Reflector object edit form, you can create a new file on the file system folder, and it will appear in Plone, without any further manual operation on your Reflector object. Nonetheless, if you want to change the Plone state on that file, you will find that it is not possible, and if you try to search for that file through the Plone search form, it will not show up. Let's try to understand the reasons of this in the next paragraph.

Almost every standard Plone behavior bases its operations on information stored in the objects it makes use of. For instance, for security and workflow services to work, they need to annotate the objects on which they are applied with specific information, and this is not easy to do with a file outside the ZODB storage. Furthermore, some services maintain a separate registry and need complete control over the content they manage. As an example, the portal_catalog tool maintains its own registry for indexing purposes, and standard implementation of the indexing mechanism in Plone is based on synchronous calls. Each content object calls methods on the portal_catalog service, such as reindexObject, every time it is known that something new needs to be registered.

In the case of Reflecto, if some third-party application or manual intervention changes the files directly on the file system, the Plone registries will not be up to date. That is why Reflecto 2.0 proposes a trade-off between showing live data, or indexing file system contents, and advising that the live data mode could slow down Reflecto quite a lot. That is also why you cannot provide any working standard workflow or security function on these kinds of content. Plone security and workflow services are very advanced features, so it should be fairly obvious why you cannot quickly apply them to a file system folder and its content.

Relational Databases

For many years, relational databases have been the de facto standard for storing data in business applications, web CMS applications included. However, Zope doesn't need a relational database to store its data. Let's try to understand the reasons of this.

ZODB vs. Relational Databases

Relational databases are founded on mathematic theory and some efficient and well-known design techniques, not to mention various powerful database management systems (DBMSs) such as PostgreSQL. Relational databases need some conditions to efficiently apply their principles to our data, and these conditions are often mismatched by generic web applications. The most important reason for this is that a typical web application has a tree-like data structure, but relational databases are most suited to flat data structures: this is usually pointed out as an "object-relational impedance mismatch." Zope applications are developed as object hierarchies, so it would be quite difficult to store each object instance we need in generic relational structures while building an application. This is why Zope developers developed the ZODB, which is now a very robust and scalable object database, with transactional support and much more. Certainly it is one of Zope's secret weapons, especially if we consider all the attention paid to ORM technologies nowadays.

Many Zope applications are completely at ease without the need to even define a relational database structure. And developers use the ZODB transparently almost everywhere. Nonetheless, there are some Zope applications that need some integration with or functionality of a relational database management system (RDBMS). Next, we'll show you how Zope has no problems solving those situations.

Adopting a Relational Database in Zope

Without providing excessively complex use cases that would be out of the scope of this book, we will glance over some of the various ways to adopt a relational database in a Plone application.

Note The Zope Book provides a complete chapter on relational databases connectivity, available at www.zope.org/Documentation/Books/ZopeBook/2_6Edition/RelationalDatabases.stx. This documentation gives the official way to integrate a relational database in a standard Zope application, but remember that we can adopt anything that Python supports to solve this problem.

First of all, we should solve the simplest problem, in which we have a relational database table storing data we need to publish in our Plone site. This can be solved easily using particular Zope 2 tools. Specifically, we can add a Database Adapter object to open a connection to the relational database we want to query, create a ZSQL Method object to set our SQL query and run it, and finally use the result produced by the ZSQL Method execution, publishing it through a Zope page template.

For the following to work, you will need access to a PostgreSQL database service. We will also assume you installed in your Zope server instance the ZPsycopgDA product, which you can get from http://pypi.python.org/pypi/psycopg2. ZPsycopgDA is part of the psycopg2 package because it depends on it, so please read its install documentation carefully to understand how to make it work on your system.

Note You can use a different database than PostgreSQL as long as you have a working Zope Database Adapter object for it.

We will also need a table to query, so let's execute this script on our PostgreSQL database service to create our database:

CREATE DATABASE plonebook
  WITH OWNER = postgres
       ENCODING = 'UTF8';
Then create the "contacts" table:
CREATE TABLE contacts
(
    id serial NOT NULL,
    name text,
    surname text,
    telephone text,
    mail text,
    CONSTRAINT id PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
ALTER TABLE contacts OWNER TO postgres;

Finally, insert some records into the table so that our test will provide some data. We are now ready to start with the Zope side.

If you correctly install ZPsycopgDA and restart your Zope service, a new item, named Z Psycopg 2 Database Connection, will appear in the ZMI Add select box in the top-right corner. Assuming we are customizing our site at http://localhost:8080/plone, let's visit the custom skin directory at http://localhost:8080/plone/portal_skins/custom/manage. In this directory, select the Z Psycopg 2 Database Connection item from the Add box. Enter postgresDA as the ID, and then enter the correct connection string to your PostgreSQL database (in our case, host=localhost dbname=plonebook user=pg_zope password=pg_zope). Leave all the other fields as is, and click Add.

You should have a new connection to your database open, and you can test it simply by visiting http://localhost:8080/plone/portal_skins/custom/postgresDA/manage_testForm, and selecting everything in the contacts table by typing in the following line:

select * from contacts

Then click Submit Query. If the connection is on, you should see the contacts you inserted in the table. Next, you need to create a proper way to use the database adapter. You'll do this using a new ZSQL Method that you'll add to the custom skin directory. As before, select the ZSQL Method item from the ZMI Add select box. Then enter getContacts for the ID and the title, and specify postgresDA for the connection ID. Now, in the Query Template box, type the following:

select * from contacts

Click the Add and Test button, and finally click Submit Query. Again, Zope should publish your contact records now, and also any time you call this ZSQL Method object (which you're going to do next).

Now, all you're missing is a nice page template to publish this data using Plone as a publishing box. So, add a new page template object named contacts_board to your custom skin directory and insert code to execute the getContacts method, acquiring it from the context. Then cycle over the resulting records. It should look like the following lines:

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:tal="http://xml.zope.org/namespaces/tal"
      xmlns:metal="http://xml.zope.org/namespaces/metal"
      xmlns:i18n="http://xml.zope.org/namespaces/i18n"
      lang="en"
      metal:use-macro="here/main_template/macros/master"
      i18n:domain="plone">
<head>
    <metal:block fill-slot="top_slot"
               tal:define="dummy python:request.set('disable_border',1)" />
</head>
<body>
<div metal:fill-slot="main">

      <h1 class="documentFirstHeading">
          Contacts
</h1>
<ul tal:define="contacts here/getContacts">
<tal:block repeat="contact contacts">
    <li tal:define="name string:${contact/name} ${contact/surname};
                 details string:${contact/telephone}, ${contact/mail};">
            <strong tal:content="name">contact's name</strong><br/>
            <span tal:content="details">contact's details</span>
            </li>
    </tal:block>
    </ul>

</div>
</body>
</html>

If you open the URL http://localhost:8080/plone/contacts_board in your browser, you should see a nice formatted template with the records from your contacts table, as Figure 10-1 shows.

Images

Figure 10-1. The contacts table records viewed in Plone

Obviously, this is a convenient way of accessing your relational database from Plone, especially considering that the ZSQL Method object is far more flexible than the simple case just shown. But this approach has some problems if you want to obtain more reusable code; besides, it adopts a specific Zope pattern that can become unmanageable if development issues arise.

We will skip all the various hybrid approaches you can adopt mixing up specific Zope and Python ways of accessing a relational database. For instance, Archetypes (covered in Chapter 9) proposed a SQL storage concept, which did not prove itself as a viable integration pattern. If you would like to examine this possibility, you might have a look at the article "Archetypes Using MySQL and PostgreSQL" on Plone.org (http://plone.org/documentation/how-to/archetypes-using-mysql).

SQLAlchemy and Plone

In this section, we will create a simple product package, implementing something similar to what we did in the previous section, but in a more Pythonic way, and without writing any SQL query to accomplish our mission, thanks to SQLAlchemy ORM technology.

Note ORM (object-relational mapping) is a programming technique to convert data from relational database structures to object-oriented coding structures. SQLAlchemy (www.sqlalchemy.org) is a popular Python SQL toolkit and object-relational mapper. It's easy to use in Python to abstract the relational database logic layer. As you will see throughout this section, SQLAlchemy let us access a relational database as we would do with a normal classes hierarchy, leaving out SQL commands as much as possible.

SQLAlchemy is not a Zope-aware package, so we will adopt Martin Aspeli's collective.lead package (http://pypi.python.org/pypi/collective.lead) to integrate the SQLAlchemy machinery with Zope. It works simply by linking SQL transactions to Zope transactions and making databases available as named utilities.

Let's start! Recalling what we did in Chapter 9, we'll create a new product package using Paster in our buildout environment. Type the following commands in a terminal window:

$ cd ~/plonebook/src
$ paster create -t plone plonebook.contacts

Answer the questions the script will ask you to create a contacts package in the plonebook namespace. In this case, we need a much less structured package than the one we implemented in Chapter 9, which is why we use the ZopeSkel plone template (using the –t plone switch). If you examine the plonebook.contacts/plonebook/contacts folder, you will find just a few files as boilerplate; that is sufficient for our basic task.

First, you'll update the configuration a bit. As stated before, you will need the collective.lead package to link SQL transactions to Zope transactions, so let's specify collective.lead as a dependency for our egg. Open the setup.py module in the root of your plonebook.contacts package, and add collective.lead in the install_requires parameter list, as follows:

...
zip_safe=False,
install_requires=[
    'setuptools',
    # -*- Extra requirements: -*-
    'collective.lead',
],
entry_points="""
...

Next, open the buildout.cfg file in your buildout root directory, and add the plonebook.contacts entries where needed under eggs, develop, and zcml parameters, as follows:

...

eggs =
 ...
 plonebook.contacts

develop =
    ...
    src/plonebook.contacts

...

[instance]
...
zcml =
    ...
 plonebook.contacts

...

Then type the following in your terminal window:

$ cd ~/plonebook
$ ./bin/buildout -v

This should download and configure everything you need to connect to your relational database through collective.lead and SQLAlchemy.

As specified in the collective.lead package documentation, to connect to the relational database, you have to configure a named utility based on the Database class provided by the package. So, let's create a new file named database.py in src/plonebook.contacts/plonebook/contacts. We'll use the empty Contacts class to bootstrap the database connection, asking SQLAlchemy to autoload the contacts table associated Python class. Type in the following:

from collective.lead import Database
import sqlalchemy as sa
from sqlalchemy import orm

class Contacts(object):
    pass

class PlonebookDB(Database):

    @property
    def _url(self):
        return sa.engine.url.URL(drivername='postgres',
                                host='localhost', port='5432',
                                database='plonebook',
                                username='pg_zope', password='pg_zope',
                                )
def _setup_tables(self, metadata, tables):
    tables['Contacts'] = sa.Table('contacts', metadata, autoload=True)

def _setup_mappers(self, tables, mappers):
    mappers['Contacts'] = orm.mapper(Contacts, tables['Contacts'])

The PlonebookDB class is your database connection named utility implementation. You specify your connection parameters through a special method named _url, used by the collective.lead Database class to open a connection to your PostgreSQL database. Then you define the table you want to map in the _setup_tables method, and finally you extract its shape from the database using the SQLAlchemy mapper class in the _setup_mappers method. The mapper defines the correlation of class attributes to database table columns. In your case, you have asked SQLAlchemy to automatically determine such correlations by setting the autoload parameter to True in the _setup_tables method.

Now, to define the final named utility, we just need to open the configure.zcml file of our package and register the plonebook.db utility within it:

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:five="http://namespaces.zope.org/five"
    i18n_domain="plonebook.contacts">

    <include package="collective.lead" />

    <utility
        provides="collective.lead.interfaces.IDatabase"
        factory=".database.PlonebookDB"
        name="plonebook.db"
        />

</configure>

As you can see, you also need to explicitly include the collective.lead package, because its configure.zcml file defines a specific factory adapter you need to let your PlonebookDB class work as expected. At this point, you should have everything in place to connect to your relational database. Easy enough!

Let's go on now with providing a browser view that's able to produce the same results we had with our Zope-specific connection method. Create a subfolder in your package, named browser, and create an __init__.py file to make it a Python package. In the terminal window, run the following commands:

$ cd ~/plonebook/src/plonebook.contacts/plonebook/contacts
$ mkdir browser
$ cd browser
$ touch __init__.py

Next, create a file named contacts.py in the browser folder, containing the following code:

from Products.Five import BrowserView
from zope.component import getUtility
from collective.lead.interfaces import IDatabase

from plonebook.contacts.database import Contacts

class ContactsView(BrowserView):

    def getContacts(self):
        db = getUtility(IDatabase, name='plonebook.db')
        contacts = db.session.query(Contacts).list()
        return contacts

Also create a contacts.pt file to ask the view class to provide the contact data, and then copy into it the contacts_board template we used in the previous section. Then make the following single-line modification:

...
<ul tal:define="contacts view/getContacts">
    ...
</ul>
...

Next, to register the browser view, create a configure.zcml named file in the browser directory, containing the following lines:

<configure
 xmlns:zope="http://namespaces.zope.org/zope"
 xmlns="http://namespaces.zope.org/browser"
 >

  <page
     name="contacts"
     for="*"
     class=".contacts.ContactsView"
     template="contacts.pt"
     permission="zope2.Public"
     />

</configure>

Finally, update the configure.zcml file in the package root to include the browser package, adding the following line:

...
<include package=".browser" />
...

Now start your Zope service, running the following commands in the terminal window:

$ cd ~/plonebook
$ ./bin/instance fg

Point your web browser to http://localhost:8080/plone/contacts; you should see the same list of contacts as before, but this time no SQL queries will be involved. Likewise, there will be no specific DBMS dependencies—you just specified postgres as the drivername parameter in the _url method of your utility. Not bad at all!

Just to push it a bit further, we will now introduce a simple form to query our contacts table by name. Modify your contacts.pt template, adding the following lines:

...
<h1 class="documentFirstHeading">
   Contacts
</h1>

<form tal:attributes="action view/name" method="get">
    <label for="contact_name">Name</label>
    <input type="text" name="contact_name" id="contact_name" />
    <input type="submit" value="Search" />
</form>

<ul tal:define="contacts view/getContacts">
...

Here, we've submitted the form to the same browser view, passing contact_name as a parameter to filter by. Now update the ContactsView class as follows:

...
class ContactsView(BrowserView):

    @property
    def name(self):
        return self.__name__

    def getContacts(self):
        db = getUtility(IDatabase, name='plonebook.db')
        query = db.session.query(Contacts)
        name = self.request.get('contact_name')
        if name:
            contacts = query.filter(Contacts.surname.like("%"+name+"%")).list()

        else:
            contacts = query.list()

        return contacts

To build the form action URL, we have provided the browser view name with a specific name method. We have also modified the getContacts method to get the contact_name parameter from the request object, and, if given, to use it to filter the SQLAlchemy query, adopting a "like" syntax. Again, we didn't need to provide any specific SQL queries.

So far, you should understand that, although relational databases are not Plone's first choice, there are no problems using them with Plone. Moreover, there are many different ways to do it—some more Zope-specific, others more Pythonic.

Note We should mention a nice Plone-related project that involves a relational database: ore.contentmirror (see http://plone.org/products/contentmirror for more details). Kapil Thangavelu released this great package in 2008, and presented it at the annual Plone Conference as a transparent layer able to mirror the content of a Plone site into a structured external data store. As stated in the package documentation, it primarily focuses on and supports out-of-the-box content deployment to a relational database, but it can be useful in a variety of cases as a way to integrate Plone with other systems without too much effort.

Accessing Plone Without a Web Browser

While Plone is an empowering application for managing content using the Web, the Web is not the only way to access Plone's management capabilities. Zope is a solid application server, providing the infrastructure for its applications to be accessed in a variety of different ways, among which are WebDAV and FTP.

Accessing Plone over FTP

It is quite easy to modify the Zope configuration file, zope.conf, to automatically start the internal FTP server or enable access to the dedicated WebDAV server. Just add the following lines to the zope.conf file:

<ftp-server>
    # valid key is "address"
    address 8021
</ftp-server>

<webdav-source-server>
    # valid keys are "address" and "force-connection-close"
    address localhost:1980
    force-connection-close off
</webdav-source-server>

You can also do the same using buildout—just add the following parameter to your buildout.cfg file in the zope2instance recipe section:

...
zope-conf-additional =
<ftp-server>
         # valid key is "address"
         address 8021
       </ftp-server>
       <webdav-source-server>
          # valid keys are "address" and "force-connection-close"
          address localhost:1980
          force-connection-close off
  </webdav-source-server>
...

Remember to run the buildout script after you modify the buildout.cfg file!

Next time you start your Zope service, it will activate the specified protocols' servers on the indicated ports.

Note FTP (File Transfer Protocol) has been widely used as the standard way of transferring files on the Internet. Zope 2 lets us access its objects using this protocol. For a more comprehensive reading about accessing Zope objects via FTP, have a look at the "Managing Zope Objects Using External Tools" section of the Zope Book, at http://docs.zope.org/zope2/zope2book/source/ExternalTools.html.

WebDAV (Web-Based Distributed Authoring and Versioning) is an extension to the HTTP protocol, advocated by the W3C, specifically aimed at enabling users to collaboratively edit and manage files on web servers. Unfortunately, it is quite a new standard, and therefore not supported by as many applications as FTP, nor always fully implemented. So, be prepared to look for the right tool to manage it on your operating system, as suggested by the "Using WebDAV" tutorial on Plone.org (http://plone.org/documentation/how-to/webdav).

But what does all this mean for the end user? Not that much—it's just FTP access we enabled, which isn't that amazing or useful to add to Plone, because Plone already does all those file transactions in an elegant, polished web user interface. The Plone web user interface is usually an easy choice both for readers and content managers: you can get full access to all of the core functionalities wherever you can log on to the site with a web browser, no matter if you are on your PC or a complete stranger's machine.

Nonetheless, some special use cases would preferably dictate simpler and more effective user interaction than the one offered by the Plone web user interface—for instance, when you need to move a large number of images or files, or when you need to upload a massive amount of original content to a new portal from the file system. In all these cases, something like an FTP client would be very useful.

Using Plone Through the WebDAV Protocol

In some other cases, it could be great to have network share–like access to your site directly in the file manager, especially if you use Plone as an intranet system, storing projects, documents, and the like in it.

This is where WebDAV comes in. However, standard WebDAV clients cannot achieve full-featured access to Plone content. For instance, Plone workflow and security are quite difficult to manage without Plone's web user interface, and, in any case, it's not possible with a standard FTP or WebDAV client.

Nevertheless, the closer we stay to the file management pattern, the better we could be satisfied with Plone FTP and WebDAV standard access. Instead, if you want to access the whole set of metadata of your Plone objects, such as their workflow state or publication dates, then you will need the Plone standard web user interface. If you are inclined to give a try to FTP or WebDAV access to Plone, it will be helpful to keep in mind the existence of the content_type_registry tool, which we introduce in the next paragraphs.

Plone inherits some of its services from the CMF layer, and one of them is especially useful to our purpose: content_type_registry. For example, when you add an image through the Plone web interface, you explicitly ask Plone to create an image content type. But what will happen if you add a new image file using an FTP or WebDAV client? You may be surprised to discover that Plone will create the right content type for you!

Plone does this via the content_type_registry tool, which has a list of default rules that define which CMF content type will be created based on specific conditions of the uploaded file. These rules may use the file extension, as well as its MIME type or some specific name-based regular expression. You can define your own rules and create your own content types as appropriate.

Note Plone reveals another advanced behavior: the ability to let you manage web pages without the need to learn HTML, and without allowing you to break the site with incorrectly entered page body text. To accomplish this, Plone's WYSIWYG HTML editor, Kupu, supplies a powerful filtering and transforming layer, which alters the page. Among other things, it doesn't allow you to insert dangerous HTML tags (as discussed in Chapter 4).

Of course, this implies that if you import HTML files through FTP or WebDAV, the files may end up showing quite a different look due to Plone's filtering feature. Additionally, if you try to modify your pages with a standard HTML editor through FTP or WebDAV, then Plone will transform your modifications to meet its filter rules.

As a final note to this section, if you need finer-grained control over Plone folders mounted via WebDAV as network shares on a Windows-operated PC, you could try Enfold Desktop. Enfold is a Plone company that has been offering both open and closed source extensions to Plone for years. One of these extensions, recently passed to the open source side, is Enfold Desktop, which offers advanced access to Plone content through the Windows file manager, such as extending its contextual menu to add workflow support at the file manager level.

Note Plone.org offers a good read about issues you may encounter while importing content in Plone: "Importing existing HTML content into Plone," at http://plone.org/documentation/faq/importing-existing-html-content-into-plone.

Integrating Plone with Other Frameworks

Plone as a CMS is quite independent with regard to integration with different systems, able to solve any need it meets autonomously. Nonetheless, Plone is a web-based CMS, and thus genuinely part of the inherently integrated ecosystem that is the Web in general.

Plone portals are coherent and self-reliant, and it is also quite easy to build a constellation of different Plone sites connected to each other in various forms.

In this section, we will outline some techniques that let Plone play with other systems: RSS files exchange, XML-RPC access to Plone, and WSGI integration.

RSS Integration into Plone

Let's start with the basics: integration techniques involving sharing content with other sites and services over the Web. For example, it's often useful to share certain types of content, such as news, with other sites automatically. The standard mode for doing this is called RSS (Really Simple Syndication). Fortunately, Plone offers RSS functionality out of the box.

Note The ability to share information among sites, or to stay tuned with our preferred news source using an automated process is a notorious problem with as big and prolific an information source as the Web. Many years ago, Netscape launched the first version of RSS. Since then, various versions of RSS and alternative formats have spread out, among which are Atom and OPML.

First of all, any Collection object exposes its content's RSS version. So, if you need to share some kind of content corresponding to some specific criteria, just create a collection stating those criteria (refer to the "Gathering Disparate Elements into Coherent Collections" section of Chapter 3 to see how to do so), and you will get a content listing in RSS form. (This is, in fact, exactly what happens if you go to a new Plone site and click the "RSS feed" link at the bottom of its News section; it actually contains a Collection object providing the link.)

Second, Plone lets you build your own RSS feeds through the Advanced Search form. Any time you go to search in Plone, on the results page you will find a link offering you search results for the same criteria in RSS format. With a good RSS reader or just Mozilla Firefox, you can easily create a personal notification system to alert you any time you want to be informed about something (e.g., the creation of new pages in a section or updated content from a specific author) using an automated Advanced Search query. Try it!

Plone 3.0 supports only RSS version 1.0, although there are products extending it to various other formats, like RSS version 2.0 and Atom, the most promising of which is Vice (http://plone.org/products/vice). We can easily implement our own RSS template, extending the default one, as well as completely rewriting it to support other standards or cover different requirements. The Zope Page Templates (ZPT) language is not HTML-specific and can be a good XML-templating language, which makes such tasks even easier.

In the case we want to publish external RSS feeds in our site, we can use the Plone RSS portlet, which we can add to any section of Plone: when you add an RSS portlet through the Plone portlet management interface, just indicate in the edit form of the portlet the number of items to show, the URL of the RSS feed, and the reload timeout to refresh the feed from the source service, and Plone will do the rest. You have seen how to configure an RSS portlet in the "Managing and Adding Portlets" section of Chapter 4. For achieving more advanced functionality, consult the "Products" section at Plone.org (http://plone.org/products) and search for "RSS."

XML-RPC and Plone

If you need a more specific automatic interaction with other services, especially online services, there are various possibilities to consider, but the simplest and most productive one is probably the XML-RPC protocol: a Remote Procedure Call protocol that uses HTTP as the transport layer and adopts XML to encode communications. We won't go into details, but a typical use case involving the adoption of XML-RPC access to Plone would be the creation of objects from external services. One specific example of an XML-RPC solution is the LeMill FSE, part of the LeMill project (http://lemill.net and http://lemill.org). LeMill FSE is a Federated Search Engine layer, which enables running a standard Plone search over multiple federated Plone sites, and it is just a matter of a few lines of Python code in which communications between different Plone sites are implemented via XML-RPC, as you can see at http://lemill.org/trac/browser/trunk/LeMillSearchTool.py.

Note XML-RPC is a forefather of SOAP (Simple Object Access Protocol). Basically, it defines a handful of data types and commands in XML used by client and server services to communicate through HTTP. A good tutorial about Zope and XML-RPC can be found on the Zope web site at www.zope.org/Members/Amos/XML-RPC.

Zope offers a very strong platform for supporting XML-RPC based applications. In fact, Zope and Plone are accessible via XML-RPC, requiring you to pass the same security checks of the standard web access.

And Now for Something Completely Different: Plone on WSGI

If you immediately got the heading title, then you are a real Pythonist! (If not, you have some Monty Python that you need to watch.) If we consider integration between different applications, the Python world offers something that shouldn't be missed: WSGI.

The Python Web Server Gateway Interface (WSGI) was proposed in 2003 by Phillip Eby, who wished to create an easy way to integrate different application server frameworks and to obtain unique final applications (www.python.org/dev/peps/pep-0333). At that time, the Python world of web application frameworks was quite crowded, and his proposal quickly reached some acknowledged implementations. Nowadays, the Python world of web application frameworks is still very crowded, but almost all of the frameworks already support WSGI or are likely to do it.

The WSGI layer is placed between the web server and the application server, so that the choice of framework is separated from the choice of web server. As declared by Eby, the goal of WSGI is "to facilitate easy interconnection of existing servers and applications or frameworks, not to create a new web framework."

The proposal suggested that WSGI would also allow for the "possibility of an entirely new kind of Python web application framework: one consisting of loosely coupled WSGI middleware components." And that is exactly what is coming true, as you will see in a while; in fact, a middleware component could act as a server to some application(s), and as an application to some server(s), all at once. Adopting such an architecture, a middleware component could, for instance, route a request to different application objects based on the target URL, after rewriting the environ parameters accordingly, or allow multiple applications or frameworks to run side by side in the same process.

The Zope 2 world was a bit behind, until Agendaless and its Zope superstars decided to recover, founding the Repoze project. Chris McDonough and Tres Seaver are the parents of a reliable collection of technologies that bridge WSGI and Zope. Agendaless reimplemented some core Zope features as WSGI middleware and applications. In this way, it's easy for Python developers to plunge Zope pieces into a WSGI environment.

As part of the Repoze project, the repoze.plone WSGI application provides a completely working Plone application served by a WSGI environment.

If you want to install it on your machine, you just need to download a working buildout and run it locally. Open a terminal window and type the following to check out the basic buildout provided with repoze.plone:

$ cd ~
$ svn co http://svn.repoze.org/buildouts/repoze.plone/trunk repoze.plone

Next, just launch the buildout in this way:

$ cd ~/repoze.plone
$ python bootstrap.py
$ ./bin/buildout -v

If everything goes right, read the instructions to continue: launch the supervisord daemon to start all the configured services, and then run the addzope2user script to create the admin user:

$ bin/supervisord
$ bin/addzope2user <username> <passwd>

Finally, just visit your running service at http://localhost:8080/manage using your web browser, log in, and create your new Plone site. It will be the same, but served in a completely different way!

At this point, you should be curious enough to ask for more information about how to fit different pieces of WSGI together with Plone—for instance, to obtain a really decoupled single-sign-on layer—but that is a matter for another book.

Summary

If you need your Plone site to integrate with other systems and applications, then this chapter should have been extremely useful for you. In this chapter, we have covered how to directly publish a file system folder through a Plone site, how to access a relational database and publish its information using Plone as a front end, how to access Plone via FTP and WebDAV, and how to syndicate your Plone content to other sites via RSS. We also introduced the XML-RPC protocol and WSGI. You could look deeper into many aspects of this chapter, and you could look into many related topics as well.

In the next chapter, you'll discover how to tackle various system architecture and deployment configuration cases.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.80.3