XML::Comma::Pkg::Mason::ParResolver(3pm)

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

DESCRIPTION
"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 handler.pl 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.

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

CONFIGURATION
"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 handler.pl, 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 handler.pl file that I often use on development servers:

  #!/usr/bin/perl
  #
  # This is a basic handler.pl 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.

COMPLEXITIES
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 handler.pl 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".

COPYRIGHT and LICENSE
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.