XML::Comma::Pkg::Mason::ParResolver - Mason/Comma packages


XML::Comma::Pkg::Mason::ParResolver knows how to serve Mason components, Comma defs and perl Modules from zipped archives.

A Comma package is a zip file with the following top-level directories:

  F<comma/> - Def (and macro and include) files
  F<mason/> - Mason components
  F<lib/> - Perl modules

The amazing PAR module handles the loading of modules from the lib/ directory. If you haven't read the PAR documentation, it's worth doing so. PAR does many interesting things, and we rely only on a small corner of its functionality.

Comma knows how to load defs from PAR files. The Configuration variable defs_from_PARs controls whether Comma attempts to load defs from PARs that have been use'ed into use. That variable is usually set to 0, so you may need to change it.

This module handles the mason/ component serving. Some Apache configuration is necessary, but with that out of the way you can do something like the following in a file:

  use PAR '/usr/local/apache/htdocs/par-demo.par';
  use XML::Comma::Pkg::Mason::ParResolver
    par_paths => {
      '/par-demo' => { par  => '/usr/local/apache/htdocs/par-demo.par',
                       attr => { color1 => '#0000ff' } }

And the mason/ directory in /usr/local/apache/htdocs/par-demo.par will look as if it is part of the component root, "aliased" to the path /par-demo.

In addition, we've specified that any calls to $m-current_comp->attr('color1')> (or any of its friends) will return the value '#0000ff', even if components inside the PAR file set that attribute differently.

Finally, we can selectively shadow any component in the PAR file by creating an actual /par-demo directory and components therein. Each time we attempt to resolve a component down any PAR alias path, we first check to see if there is an "ordinary" component that we can use.


There is a demo file, called par-demo.par, distributed with the XML::Comma distribution in the same directory as this source file.


XML::Comma::Pkg::Mason::ParResolver needs to handle several phases of the Apache request. Mostly, it can set up to do this itself, but it is necessary to manually specify a PerlTransHandler in your httpd.conf (or equivalent). I use these two lines, in the top level of my conf files:

  # in httpd.conf
  PerlModule       XML::Comma::Pkg::Mason::ParResolver;
  PerlTransHandler XML::Comma::Pkg::Mason::ParResolver::trans_handler

Then, in your, you'll need to use XML::Comma::Pkg::Mason::ParResolver, supplying as arguments your PAR path information. (You can also supply a verbose =&gt; 1 argument, to have this module print out voluminous debugging info to the Apache error log.)

Here is a simple file that I often use on development servers:

  # This is a basic using XML::Comma::Pkg::Mason::ParResolver.

  package HTML::Mason;

  # Sample Mason handler.

  use HTML::Mason;
  use HTML::Mason::ApacheHandler;
  use Apache::Constants qw(:common);
  use Apache:

  use strict;

     package HTML::Mason::Commands;
     use vars qw( $auth );

     use Apache::Util;
     use XML::Comma;

  use PAR '/usr/local/apache/htdocs/par-demo.par';
  use XML::Comma::Pkg::Mason::ParResolver
    verbose   => 1,
    par_paths => {
      '/foo'      => '/usr/local/apache/htdocs/foo.par',
      '/par-demo' => { par  => '/usr/local/apache/htdocs/par-demo.par',
                       attr => { color1 => '#0000ff' } }

  my $ah_show_error = HTML::Mason::ApacheHandler->new
     comp_root      => '/usr/local/apache/htdocs',
     resolver_class => 'XML::Comma::Pkg::Mason::ParResolver',
     data_dir       => '/usr/local/apache/mason_data',
     error_mode     => 'output',

  sub handler {
    my ($r) = @_;
    my $status = $ah_show_error->interp->resolver
      ->simple_handle_request ( $r, $ah_show_error );
    return $status;

This should work for you too, once your comp_root and par_paths are adjusted.


You may have noticed the simple_handle_request method, used in our handler sub above. Here is the code for that method, in its entirety:

  sub simple_handle_request {
    my ( $self, $r, $apache_handler ) = @_;

    return DECLINED  if  $r->content_type  and
                         $r->content_type =~ m|^httpd|;

    if ( $r->content_type                 and
         $r->content_type  !~  m|^text| ) {
      if ( $r->pnotes('PAR') ) {
        return $self->send_raw_file ( $r );
      } else {
        return DECLINED;

    return $apache_handler->handle_request ( $r );

Many setups have complex setups to determine whether (and how) Mason should serve top-level requests. If you need to integrate a ParResolver into such a setup, you'll need to code your own version of the logic above.

It's important to avoid asking the ParResolver to handle "httpd/*" content types. Apache uses some heavy wizardry under the covers to make requests for directories to eventually turn into requests for index.html files. (And along the way pick up missing trailing slashes.) We're not going to be able to do this as well as Apache, so we needs to get out of its way as much as possible.

It's also worth noting that PAR packages will often include binary files that need to be served without the benefit of Mason componentization. The simple_handle_request routine assumes that all "text/*" content types are fair game for Mason, but that all other content types will be sent byte-for-byte to the client. Your rules for this may differ.

Components that are served from PAR archives belong to the class XML::Comma::Pkg::Mason::ParComponent, which is a subclass of HTML::Mason::Component::FileBased.


This code is copyright 2003 AllAfrica Global Media.

Like all of the XML::Comma distribution, it is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version.