LJ Archive

At the Forge


Reuven M. Lerner

Issue #113, September 2003

The content management behind Salon and other popular sites is friendly to use for your Web site's writers and editors.

Over the past few months, we have looked at a number of different content management systems (CMSes) based on Zope. Of course, Zope is not the only game in town when it comes to open-source content management systems. One increasingly more prominent package is Bricolage, written and maintained largely by David Wheeler and based on mod_perl and PostgreSQL.

Bricolage is designed to be used by nontechnical people. True, it takes a fair amount of experience to modify and maintain Bricolage. But, whereas the people who use Apache or Perl generally are programmers or system administrators, the people who use Bricolage the most are the writers, editors and producers of a Web site.

Bricolage also has managed to acquire a fair amount of real-world experience. Apache and Perl needed to prove themselves for many years before they were accepted as part of the mainstream; Bricolage has been part of Salon magazine's CMS for a while, and sites such as eWeek and the Register are in the process of moving over. Moreover, professional publications not often known for their positive views of open-source software recently have begun to evaluate and review Bricolage. Most have found it to be an excellent package, one that rivals proprietary software costing hundreds of thousands of dollars.

This month, we take an initial look at how to install and begin using Bricolage. Over the next few months, we will look at it from a number of perspectives, examining ways in which we can customize and use Bricolage for different types of sites and publications.


The core of every CMS is a database. Commercial CMS software typically uses Oracle or Microsoft's SQL Server as the back-end database server. Many open-source projects, including many of the systems based on PHP, use MySQL. Bricolage, by contrast, uses PostgreSQL for its back-end storage.

PostgreSQL often is known as “the other” open-source database, and it has long supported the notion of a transaction, allowing you to group several database queries or commands into a single all-or-nothing group. PostgreSQL also supports other functionality that serious database operators expect, including views, user-defined functions, subselects, unions, foreign keys and integrity checks. PostgreSQL also supports Unicode, which is increasingly important for handling multilingual sites.

Bricolage uses PostgreSQL for its back-end storage, but the application itself is written in Perl. There are at least two ways to run server-side Perl programs for the Web: CGI, which is slow, safe and portable, and mod_perl, which is fast, potentially unsafe, and works only with Apache. Bricolage works under mod_perl, meaning that its code—which is written as a set of Perl modules—is compiled once, cached in memory as Perl “opcodes” and executed multiple times. As a result, Bricolage executes quickly.

As I mentioned above, mod_perl works only under Apache. Although constant development work is being done on mod_perl for Apache 2.x, you should expect to run mod_perl for only Apache 1.x as of this writing, in early June 2003. Because Apache 1.x runs as a set of processes rather than multiple threads within a single process, no way exists to do true database pooling among the various child HTTP servers. However, keeping an established database connection alive between Apache and PostgreSQL is possible using the Apache::DBI module. Bricolage does exactly this, ensuring that database connections do not need to be re-established each time a user makes a request.

Finally, Bricolage presents its data to the end user with a set of Perl/HTML templates. Many such templates are available for Perl in general and for mod_perl in particular. I have been a longtime fan of HTML::Mason.

As you can tell, one of the reasons I am so enthusiastic about Bricolage is it combines some of my favorite technologies—PostgreSQL, mod_perl, Apache and HTML::Mason—into a single application that is good for end users.


Installing Bricolage is not a simple process. This situation is not the fault of the Bricolage authors or maintainers but, rather, a result of Bricolage using so many different modules from the Comprehensive Perl Archive Network (CPAN). Currently, installation still is not as smooth or easy as it could be, but things have improved over time, with easier installation accompanying each version.

The easiest way to install Bricolage, after you have already installed Perl, Apache and mod_perl—as a static module, not as an Apache dynamic shared object (DSO)—is to use the pseudo-module Bundle::Bricolage defined in CPAN. Normally, you can install a Perl module with the interactive CPAN tool by first starting the CPAN shell with perl -MCPAN -e 'shell' and then typing install Bundle::Bricolage at the prompt. If you are running a relatively recent version of Perl, and if you have defined the environment variables PGINCLUDE and PGLIB, all of the modules should download, compile and install perfectly.

This is a long and involved process, however, and something is bound to go wrong, if you're like me, with CPAN and double-checking that you have installed everything you need by trying one last time to install Bundle::Bricolage. For example, I installed LWP and Bundle::CPAN using the interactive CPAN shell. I then tried to install Bundle::Bricolage; the installation (on a virtual colocation system running Red Hat Linux 7.3) failed for Cache::Cache the first time around but succeeded the second time. CPAN dependencies sometimes can be tricky, and not all modules clearly define and indicate theirs. It also failed on DB_File (because the RPM for db3-devel was not installed), causing problems with the installation of Apache::Session, which in turn caused problems with HTML::Mason, on which Bricolage depends. And, there were problems installing libapreq (because Apache was already running on the same port number) and XML::Parser (because the expat-devel RPM wasn't installed). Luckily, trying to install a CPAN bundle indicates (at the end) which packages didn't install cleanly. You always can try to re-install the bundle, in which case the CPAN shell tells you which modules already are installed and which still need to be installed.

Bundle::Bricolage does not install the Bricolage modules but the modules on which Bricolage depends. So after you have double-checked that Bundle::Bricolage is working correctly, download the latest Bricolage tarball from the Bricolage home page (www.bricolage.cc), open it up and type make. The Makefile checks to make sure all required and some optional Perl modules have been installed, and then asks if you want to install any that are missing. It also checks that mod_perl was compiled statically (and not as a DSO) and that PostgreSQL is installed. Finally, it asks for a number of user names and passwords that Bricolage needs in order to set up its databases and install its HTML::Mason components on the system.

Once you answered all of the questions, you can start the installation with:

make cpan && make test && make install

This command downloads and installs necessary modules from CPAN, tests the Bricolage installation to ensure that it is working right and, if all went well, installs Bricolage itself.

It's easy to run into some problems when installing Bricolage, but overall the installation was impressively easy, given the complexity of the system. The Makefile offered intelligent defaults, forced me to provide a password to the “bric” PostgreSQL user and generally ensured that things were running correctly and smoothly.

Once everything was installed, I invoked bric_apachectl start to start Apache, pointed my Web browser at the root directory and was greeted with a screen asking me to log in. The installation had succeeded. As suggested by the Bricolage documentation, I immediately changed the administrative password, which is appropriately set to “change me now!” by default.

At this point I should mention that Bricolage uses a fair number of pop-up windows. I personally happen to dislike pop-ups, even when they are not used in the context of advertising. Although I understand the nature of user interfaces in HTML often requires pop-ups for the natural flow of information, I still wish Bricolage used them a bit less. Moreover, a number of the internal links depend on JavaScript, which means I cannot use my beloved middle mouse button to open a new tab instead of a new window. But, this and other minor blemishes do little to change the fact that Bricolage is truly an amazing package.

Behind the Scenes

Bricolage consists of several parts: a data model in PostgreSQL, a number of Perl modules and a number of front-end templates that display information retrieved by the modules. In this way, it is similar to other sophisticated database-backed systems. Indeed, although Bricolage attempts to solve a more limited set of problems than OpenACS does, and obviously uses different technologies to accomplish its goals, the separation of data, libraries and templates is quite similar to that system and to many other systems using a three-tier architecture.

If you look in the inst directory of the Bricolage package, you see the PostgreSQL database definitions used by the system. If you are new to PostgreSQL, you might be a bit surprised by some of the things you see there, such as sequences and constraints.

Sequences are a special kind of numeric object in PostgreSQL whose values can never be reused. They are most often used to ensure that IDs in the system are unique, especially when used as primary keys. If you define a PostgreSQL column to be SERIAL rather than INTEGER, you actually are creating a sequence behind the scenes. Older versions of PostgreSQL made it inconvenient to drop a table with a SERIAL column; you had to drop the table and then drop the sequence associated with the SERIAL column as well. As of PostgreSQL 7.3, however, removing a table automatically removes any sequences that were associated with its SERIAL columns.

Constraints allow the database to reject INSERT and UPDATE statements that set values outside of a particular range. For example, Bricolage defines a media table in which every element has a priority between 1 and 5 but a default of 3. The column definition thus looks like:

priority   NUMERIC(1,0)  NOT NULL
                         DEFAULT 3
                         CONSTRAINT ck_media__priority
                         CHECK (priority BETWEEN 1 AND 5)

The constraint can be given an optional name, in this case ck_media_priority. This makes it easier to find and fix errors; if you try to insert an invalid value into this column, PostgreSQL indicates the name of the violated constraint. This helps quite a bit when debugging problems with the database definition as well as with the applications using the database.

Also a bit surprising is that a small number of functions are defined. PostgreSQL makes it possible to define functions in a number of different languages, including standard SQL and the procedural Pl/PGSQL, as well as database-enhanced versions of Perl, Python and Tcl.

Of course, the core of the Bricolage data model is the tables. A person table is used to describe system users, an org table describes organizations and then a person_org table handles the intersection between these two tables.

Indeed, it's possible to achieve a good understanding of what's happening inside Bricolage without too much difficulty by simply looking at the database definitions. For example, I added a new story—a glowing review of Core Perl—to Bricolage using the default administrative user account with all of the defaults. This inserted a new record into the story table, assigning it a priority (as we saw above), a date of publication and expiration, a version number (as Bricolage also handles versioning of articles) and an indication of whether the story has been published.

Several keys foreign to other tables demonstrate how this particular article fits into the system. We can see it was created by the administrative user, because the usr column points to the usr table; it is part of the story workflow, distinct from other workflows that have been defined, and referenced in a foreign key from the workflow__id column; it came from the edit desk, distinct from other desks, such as copy, legal and publishing, and referenced with a foreign key to the desk table; and it is considered to be a book review element, because its element__id column points to the element table. Each of these other tables is connected to still other tables that provide additional auxiliary information, from burners to group IDs to formatting information.

In short, the story table sits close to the center of the Bricolage data model—just as it should be given that a CMS is centered around content, of which stories are the primary example. Indeed, if you are new to the world of relational databases or want to see an open-source project that uses them in a sophisticated way, you would do well to look at Bricolage.


This month, we took our first look at Bricolage, an open-source content management system based on mod_perl and PostgreSQL. We learned how to install and begin using it and then dove a bit into the data model that Bricolage uses to keep track of the various story elements.

Next month, we'll look at how to define elements, categories, media types and burners, which will let us not only poke around with the system but actually publish documents to our own private Web site. Following that, we will dive a bit more deeply into the system, examining the Mason templates that allow us to move away from the default Bricolage look and feel, toward something closer in spirit to the design we want for our own personal Web sites.

Reuven M. Lerner (reuven@lerner.co.il) is a consultant specializing in open-source Web/database technologies. He and his wife, Shira, recently celebrated the birth of their second daughter, Shikma Bruria. Reuven's book Core Perl was published by Prentice Hall in early 2002, and a second book about open-source Web technologies will be published by Apress in 2003.

LJ Archive