Press Releases with Mason

To learn more about building dynamic web sites, Mr. Lerner presents an application for reading the news using Mason and MySQL.

Last month, we took an initial look at Mason, a template system that sits on top of mod_perl and allows us to create fast-executing dynamic web sites built out of small components.

This month, we will look at a simple application built in Mason—a system to display the latest press releases on a corporate site. Of course, such a system could be tailored in a number of ways, including an on-line newspaper or other publication in which information changes on a regular basis. In creating this small site, we will see some of the steps involved in working with Mason.

Creating the Database

The core element of our news system will be a relational database. I will use MySQL in these examples, although any relational database system should work fine.

I created a new MySQL database called “atfnews” on my MySQL server and assigned privileges so that the user atfnews can connect using the password “atfpass”. I then created the following two tables:

CREATE TABLE Categories (
     category_id SMALLINT UNSIGNED AUTO_INCREMENT,
     category_name VARCHAR(25) NOT NULL,
     PRIMARY KEY(category_id),
     UNIQUE(category_name)
);
CREATE TABLE Articles (
     article_id MEDIUMINT UNSIGNED AUTO_INCREMENT,
     category_id SMALLINT UNSIGNED NOT NULL,
     posting_date TIMESTAMP NOT NULL,
     headline VARCHAR(30) NOT NULL,
     body TEXT NOT NULL,
     PRIMARY KEY(article_id),
     UNIQUE(category_id, headline)
);

As you can probably tell from their names, the Categories table contains a list of category ID numbers and names. The Articles table contains several more pieces of information, including an article ID, the category ID into which an article should be placed, the date and time at which the article was posted, the article's headline and its body. We ensure no two articles in a given category have the same headline with a UNIQUE clause at the end of our CREATE TABLE statement.

The posting_date column takes advantage of MySQL's TIMESTAMP data type. This type automatically inserts the time and date of the latest INSERT or UPDATE to a given row. In this way, we can easily determine when news stories were added to the database, without having to enter or keep track of the information ourselves.

In order for our news system to work, we will need to create at least two different sets of components. One set will allow users to enter news items into the database (i.e., perform INSERTs), and the second will make it possible to retrieve items from the database (i.e., perform SELECTs). In a production setting, we would probably want to restrict posting access to a selected number of users. This would be possible with a standard .htaccess file, which allows users to restrict access to individual files or directories, or with a more sophisticated system that stores user information in a database.

Structuring the Components

One of Mason's strong points is its use of components. Components are actually Perl subroutines, cleverly disguised in the form of HTML files with some Perl thrown in. (Mason's parser performs the underlying magic that turns components into subroutines.) This structure means that repeated functionality can be packaged into one component, then invoked from within other components.

Listing 1

For example, Listing 1 contains a component called “database-connect.comp”. This component returns a value, rather than producing HTML output. Its purpose is to connect to a database server and return a database handle, typically called $dbh. By centralizing this connection code, we can easily move our site from one server to another, changing only the relevant $host, $user, $password and $database variables as necessary.

Once database-connect.comp has been configured, any component on our system can receive a valid database handle with the following code:

<%init>
my $dbh = $m->comp(database-connect.comp);
</%init>

The above code takes advantage of Mason's object-oriented interface, using the predefined $m object to invoke another component.

By placing the assignment inside of <%init>, we ensure that the component will connect to the database before anything else occurs within the component. However, this also means we are creating a new lexical variable ($dbh) with each invocation of the component.

It would be slightly more elegant to perform the above assignment within a <%once> section, creating $dbh a single time and keeping the value around. However, <%once> sections are executed outside of the Mason component context, meaning they cannot invoke methods on $m. Moreover, <%once> sections are invoked before new Apache child processes are created, which a $dbh object might not like. Thus, it is common to define $dbh in a <%once> section, but to perform the assignment in <%init>:

<%once>
my $dbh;
</%once>
<%init>
$dbh = $m->comp(database-connect.comp);
</%init>

The plain-vanilla mason.pl (or “handler.pl”, as the Mason documentation describes it) configuration file that comes with the Mason distribution is almost good enough for this system to work. We need to load only Apache::DBI, a wrapper module that works with DBI within the mod_perl environment, ensuring that database connections are created and dropped only as necessary.

In order to load Apache::DBI, we need to put a use Apache::DBI statement in mason.pl, which is loaded with a PerlRequire statement in httpd.conf. In order to save some memory, we insert a PerlModule Apache::DBI line into httpd.conf. This ensures the module is loaded into memory before Apache splits into numerous child processes. The module might still require a fair amount of memory, but at least that memory will be shared among all Apache processes rather than requiring each one to have its own copy.

______________________

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState