>From the docs:

> You must call clean_request_args() on the ApacheHandler object at the end of
> the request, unless you are making a new ApacheHandler object for every
> request. Otherwise bad things will happen.
> 
> This is lame, so if someone thinks of a better way to do this, I'd be happy to
> hear about it.

In my massively more complicated (in both the good and bad senses of the
word), but spiritually similar Mason-using WebApp framework, I do something
like this:

---

    <LocationMatch "^/foo/bar">
      PerlSetVar WebAppClass "WebApp::Foo::Bar"
      SetHandler perl-script
      PerlHandler Apache::WebApp
    </LocationMatch>

---

    # Apache/WebApp.pm

    our(%Apps, $Interp); # caches

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

      $self = $self->new($r)  unless(ref $self);
      $self->sanity_check() or return $self->status;
      my $app = $self->app;
      $self->parse_query($r, $app)  or return $self->status;

      return $self->handle_request($r, $app);
    }

    ...

    # "app" is a "get, set, init" attribute (c.f. Class::MethodMaker)
    sub init_app 
    {
      my($self) = shift;

      my $r = $self->apache_request;

      my $class = $r->dir_config('WebAppClass')
        or die "No WebAppClass defined for this location: ",  $r->uri;

      if($r->dir_config('WebAppNoAppCache'))
      {
        return $class->new();
      }
      else
      {
        return $Apps{$class} ||= $class->new();
      }
    }

    sub init_mason_interp { $Interp ||= ... } # more "get, set, init"

    sub handle_request
    {
      my($self, $r, $app) = @_;

      $app->refresh();

      $app->params($self->params);
      $app->mason_interp($self->mason_interp);

      $app->run();

      my $status = $app->status;

      $app->clear();

      return $status;
    }

---

    # WebApp/Foo/Bar.pm

    package WebApp::Foo::Bar;

    use strict;

    use WebApp;
    our @ISA = qw(WebApp);

    sub root_uri { '/foo/bar' } # duplicated, but oh well
    ...

---

Basically, I try to separate the thing that dispatches incoming requests
(Apache::WebApp) and the things that are dispatched to (the actual apps,
e.g. WebApp::Foo::Bar)

Every <Location*> directive has the same PerlHandler (Apache::WebApp) but
different WebAppClass  settings.

Of course, I'm free to subclass any of these classes to make some sort of
specialized behavior, but so far, the basic "dumb caching" dispatcher
(Apache::WebApp) has done everything I need.

But getting back to the point of this post, Apache::WebApp is where I do all
the per-request setup and cleanup, not in the apps themselves.  That way,
writing a WebApp doesn't involve worrying about any of the boring setup and
cleanup stuff that every app needs to do in order to work correctly (e.g.
Not have any stale data left over)

Session cleanup/save-back can be done either in the Apache::WebApp
dispatcher or at the end of the app objects' run() method.  In practice, I
do it in the dispatcher and also in some apps, using a save_if_modified()
method which is inexpensive enough that I don't care about duplicated calls.

You'll also notice that I do a "$app->refresh" before and a "$app->clear"
after processing a request in the dispatcher.  This is because some apps may
choose to "empty" themselves when not in use, even if they app object is
still cached in %apps.  So "clear()" would really clean out all data
structures, while "refresh" would rebuild them before the next run.

-John


-- 
Report problems: http://perl.apache.org/bugs/
Mail list info: http://perl.apache.org/maillist/modperl.html
List etiquette: http://perl.apache.org/maillist/email-etiquette.html

Reply via email to