Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

Subclassing Apache::Request?

by tadamec (Beadle)
on Aug 11, 2004 at 01:11 UTC ( #381826=perlquestion: print w/ replies, xml ) Need Help??
tadamec has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monks,

I'm trying to create a subclass of Apache::Request for an application here at work, and I just can't seem to get my head around why it's not working.

The current application passes data to various functions via Apache::Session::Postgres and there is no consistency between the (many) developers who've worked on the system; in one function, everything may be localized into a session "namespace", while another may dump the variables directly into the root of the session hash, or they may combine the two. I'd like to fix this. The data still needs to be stored in some sort of session, as most of the application is multiple, "wizard" type forms.

I figured it would be nice to subclass the Apache::Request object and place various methods for storing the values in the inherited request object. I can't seem to get this working and I've hit a wall. I've got this so far:

# Apache::Request subclass use strict; use Log::Log4perl; package My::Apache::Request; use Apache::Request; sub new { my ( $class, @args ) = @_; return bless { r=>Apache::Request->new(@args) }, $class; } sub LOGGER { my $self = shift; my $log = shift || 'WebApp'; return Log::Log4perl->get_logger( $log ); } 1;

Then, I have a handler module called from a PerlHandler My::Apache::Handler line in the httpd.conf file. That handler doesn't do much, as I've distilled it down to nothing during debugging:

# Handler use strict; package My::Apache::Handler; use base qw( My::Apache::Request ); use Apache::Constants qw( :common :response ); sub handler { my $r = shift; $r->LOGGER->debug('Whatever'); $r->send_http_header(); print "The Handler.\n"; return OK; } 1;

If I comment out the $r->LOGGER line, it works OK, otherwise I get a "Can't locate object method" error.

Obviously, I'm not understanding either how to subclass an Apache::Request object properly, or my understanding on how mod_perl works is just not complete. Any ideas on what I'm doing wrong?

Update: Big thanks to everybody who's offered help on this one. I've learned so far that I have to unlearn everything I know about mod_perl. Maybe that will help me solve my problem. :)

Comment on Subclassing Apache::Request?
Select or Download Code
Re: Subclassing Apache::Request?
by PodMaster (Abbot) on Aug 11, 2004 at 01:33 UTC
    In sub My::Apache::Handler::handler, what is $r? I think you'll be suprised by what you find out.


      Of course, I should have tried out print ref $r;, but my brain wouldn't allow me to see the obvious.

      Ok, that proves that mod_perl is a bigger black box to me than I originally thought.

      So, I guess the question I should be asking is: what is the best way to accomplish what I'm trying to do?

      I'm beginning to believe that subclassing the request is not the best way to do it, as the $r object I've been passing around in every mod_perl project I've ever worked on is not, in fact, an Apache::Request.

      If I do something like this:

      sub handler{ my $apr = shift; my $r = $apr->request; # Do something. return OK; }
      I can pass around my modified request object, but it will be an actual request rather than an instance of the Apache object.I still get an Apache object. Now that I've created my Apache::Request subclass, how do I use it?

      Have any links to good articles discussing mod_perl internals that might be of assistance? I've gone beyond the books and links I know about, I'm affraid.

      Thanks for the answer!

      UPDATE: Struk out my wrongness.

Re: Subclassing Apache::Request?
by ikegami (Pope) on Aug 11, 2004 at 03:14 UTC

      I fail to see much difference between the two, actually. My subclassing example was taken from the Apache::Request man page under their subclassing section.

      When I modified my Apache::Request object as was in the docs, it still broke exactly the same.

      I guess I don't understand how I should be doing this. How do I get the server to return my new object instead of a generic Apache object. Or, how do I get the server to return my object blessed as an Apache object, instead of returning a generic Apache::Request object?

      I'm even more confused now than when I started.


        I think the short answer is, you can't/don't. No matter how hard you try, handler() will always receive a vanilla Apache object

        So the next best thing would be to always start out your handlers like so:

        sub handler { my $r = shift; my $my_r = My::Apache::Request->new($r); # do interesting things with $my_r }

        Or perhaps you can create something like the Apache->instance() method, and do something like:

        # somewhere in your code... my $r = My::Apache::Request->instance; # in My::Apache::Request; package My::Apache::Request; use base qw(Apache::Singleton); # or something like it sub _new_instance { my $class = shift; return $class->new(r => Apache::Request->instance); }
        What you are failing to understand here is that your handler is not an object, it is just a class. In fact, it's not even called as class unless you tell mod_perl to use method handlers, which you haven't done here. In the examples in the docs, someone subclasses Apache::Request and then instantiates an object like this:
        my $apr = My::Apache::Request::Subclass->new($r);
        That is not what happens when mod_perl calls your handler. It doesn't call new, since new() is not a special method in Perl. It calls handler (well, you could tell it to call something else, but it's not important), passing an Apache::request object (note the lowercase r) as the only parameter. This object is normally referred to as $r, and it's the same thing you get by calling Apache->request().

        At this point, you can create an Apache::Request object by passing $r to Apache::Request->new(), or instantiate a subclass of Apache::Request in the same way. You can even make it so that other people will get your subclass object when they call Apache->request() by calling it as a set method:

        However, there is almost never a good reason to subclass Apache::Request and I don't understand why you think this will help with your session management woes. Apache::Request has nothing to do with session management. It only exists for the current request and nothing in it is saved when it goes away. So, please explain what you are really trying to do, and maybe I can suggest a better solution.
Re: Subclassing Apache::Request?
by tadamec (Beadle) on Aug 11, 2004 at 19:41 UTC

    Thanks to everybody who's set my mind straight regarding mod_perl. I've discovered through this that subclassing the Apache::Handler isn't the best way to do this.

    I'm going to go back and rearchitect some of the main application to give me this functionality. None of the "action" objects of the app are decdendant classes, and the constructor for each of the classes are exactly the same, so that's where I'll put the magic in.

    I'll go back and write an "Action" object that the rest of the objects will use as a base class, and add methods to fiddle with the session for each object. The session will be passed to the constructor, as it is now, and I'll rewrite the per-object session manipulation to use new methods.

    This will allow me to emulate private namespaces within the session transparently by having the parent Action object interrogate who the caller is and create a "private" and "public" namespace that the default methods will deal with.

    All in all, it's not the solution I wanted, but I think it's the right one; Apache::Handler subclassing would have worked (if mod_perl worked the way I used to think it did :), but having application-type logic contained within the application, instead of the web server classes, makes for a more logical grouping of functions.

    Thanks again, everybody! I never would have seen this path if you weren't so patient in explaining why my world view was wrong.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://381826]
Approved by ysth
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (7)
As of 2014-12-28 16:21 GMT
Find Nodes?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?

    Results (182 votes), past polls