Keep has asked for the wisdom of the Perl Monks concerning the following question:

monks,

for 10 years Ive been able to find any answer I ave needed here, or on Stack Overflow. Today, neither have helped, much.

My need is to Manhandle Apache::Session::* Similar to the way MasonX::Request::WithApacheSession used to. However Im using Apache2, mod_perl2 and well, MasonX is pretty broken there. I'm still using HTML::Mason, but with my owe Session Handler. This gives me the flexability to switch Data Sources from say Postgres to MySQL (Not that I would, but you never know). Also, If I can get this code functioning well enough, I'd happily submit it to CPAN to have a working workaround for MasonX breakage. (MasonX::Request::WithApache2Session and MasonX::Request::WithApacheSession2 do not work at all). The code follows.

M42C::Web
package M42C::Web; use 5.008009; use strict; use warnings; use M42C::Web::Session; our @EXPORT = qw(); our $VERSION = '2.0.01'; sub new { my $this = shift; my $class = ref $this || $this; my $self = {}; my $r = shift; bless($self, $class); $self->{_r} = $r; return $self; }; sub session { my $self = shift; return M42C::Web::Session->new( ${$self->{_r}} )->session(); }; 1; __END__
M42C::Web::Session.pm
package M42C::Web::Session; use strict; use warnings; use CGI::Cookie; use Carp; use DBI; sub new { my $this = shift; my $class = ref $this || $this; my $self = {}; my $r = shift; bless($self, $class); my %params = @_; $self->{_r} = $r; $self->{_commit} = $params{AutoCommit}; $self->getConnection(); if($self->getCookie) { $class->getSession(); } else { $class->createSession(); }; return $class; } sub getConnection { my $self = shift; return if( $self->{_dbi} ); my $sessionClass = $self->{_r}->dir_config->get("M42CSessionCl +ass"); eval { require $sessionClass; $sessionClass->import(); 1; } or do { my $err = $@; die($err); }; my $dbh = DBI->connect( $self->{_r}->dir_config->get("M42CSessionDataSource"), $self->{_r}->dir_config->get("M42CSessionDataUsername" +), $self->{_r}->dir_config->get("M42CSessionDataPassword" +)); $self->{_dbh} = $dbh; } sub session { my $self = shift; my %cookies = CGI::Cookie->fetch(); if($cookies{'sessionid'}) { $self->{_session} = $self->getSession( $cookies{'sessi +onid'}->value() ); } else { $self->{_session} = $self->createSession(); }; return $self->{_session}; }; sub getCookie { my $self = shift; my %cookies = CGI::Cookie->fetch(); if($cookies{"sessionid"}) { return $cookies{"sessionid"}; }; return undef; } sub setCookie { my $self = shift; my $sid = shift; my $cookie = CGI::Cookie->new( '-value' => $sid, '-name' => $self->{_r}->dir_config->get("M42CCookieNam +e") || 'sessionid', '-expires' => $self->{_r}->dir_config->get("M42CCookie +Expires") || 0, '-domain' => $self->{_r}->dir_config->get("M42CCookieD +omain"), '-path' => $self->{_r}->dir_config->get("M42CCookiePat +h") || '/', '-secure' => $self->{_r}->dir_config->get("M42CCookieS +ecure") || undef, '-httponly' => $self->{_r}->dir_config->get("M42CCooki +eHttp") || undef ); $self->{_r}->headers_out->add("Set-Cookie", $cookie); } sub getSession { my $self = shift; my $cookie = $self->getCookie(); return $self->createSession() if (! $cookie); my %session; tie(%session, $self->{_r}->dir_config->get("M42CSessionClass") +, $cookie->value(), { Handle=>$self->{_dbh}, Commit=>$self->{_r}->dir_config->get("M42CSessionAutoC +ommit") }); return \%session; }; sub createSession { my $self = shift; my %session; tie(%session, $self->{_r}->dir_config->get("M42CSessionClass") +, undef, { Handle=>$self->{_dbh}, Commit=>$self->{_r}->dir_config->get("M42CSessionAutoC +ommit") }); if($self->{_r}->dir_config->get("M42CSessionUseCookie")) { $self->setCookie(\%session); }; return \%session; }; 1; __END__
And Finally the autohandler
<%init> # $m->comp('/comps/session.comp'); use Data::Dumper; use M42C::Web::Session; my $eng = M42C::Web->new(\$r); </%init> <pre> <% Dumper($eng->session) %> </pre>
The Error I receive is:
Can't locate Apache::Session::Postgres in @INC (@INC contains: /opt/m4 +2c/managed/opt/perl/5.8.9/lib/5.8.9/x86_64-linux /opt/m42c/managed/op +t/perl/5.8.9/lib/5.8.9 /opt/m42c/managed/opt/perl/5.8.9/lib/site_perl +/5.8.9/x86_64-linux /opt/m42c/managed/opt/perl/5.8.9/lib/site_perl/5. +8.9 . /opt/m42c/managed/opt/httpd) at /opt/m42c/managed/opt/perl/5.8. +9/lib/site_perl/5.8.9/M42C/Web/Session.pm line 39. ... 35: return if( $self->{_dbi} ); 36: 37: my $sessionClass = $self->{_r}->dir_config->get("M42CSessionCl +ass"); 38: eval { 39: require $sessionClass; <-- Offending line 40: $sessionClass->import(); 41: 1; 42: } or do { 43: my $err = $@;

Obviously my perl istallation is frameworked, and I have confirmed that Apache::Session::Postgres is in fact installed with

perl -MApache::Session::Postgres. Just for kicks I have tried "using" +the module as well to no effect. As well, if the require line is fail +ing, WHY is blowing through the eval. Should it not be blowing at the + die line below it? <code> [shell]$ locate Postgres.pm |grep "Apache/Session" /opt/m42c/managed/opt/perl/5.8.9/lib/site_perl/5.8.9/Apache/Session/Po +stgres.pm /opt/m42c/managed/opt/perl/5.8.9/lib/site_perl/5.8.9/Apache/Session/St +ore/Postgres.pm
Any and all guidance is much appreciated.

Replies are listed 'Best First'.
Re: failure to require an installed module + eval fails to trap? (!bareword)
by tye (Sage) on Jul 26, 2015 at 05:56 UTC

    Note that require Foo::Bar; is the same as require 'Foo/Bar.pm'; which is not the same as require 'Foo::Bar';. So you need to transform your package name into a (relative) module file path if you want to use such in require $string;.

    - tye        

Re: failure to require an installed module + eval fails to trap?
by syphilis (Archbishop) on Jul 26, 2015 at 04:51 UTC
    Just for kicks I have tried "using" the module as well to no effect

    I presume that means the module loaded ok. (Please correct me if that's wrong.)

    Should it not be blowing at the die line below it?

    There's no "die" in the snippet of code (lines 35 to 43) that you've given.
    Update: but there is a "die" at the next line (line 44) - and that's where the script is, in fact, dying.
    However, because, $err ends with a newline, you don't get the "at line 44" in relation to the die.
    The "at line 39" is where the error occurred - not where the script died.
    If you chomp $err; before you die($err); you should see what I mean.

    I can't put my finger on the reason for the "Can't locate Apache::Session::Postgres" error. Perhaps related to some permissions problem ?
    I seem to recall that there have been occasions where "Can't locate" should really have been "Can't load" - because the module was actually located ok, but could not be loaded (because of permissions issues).

    What does the following command output:
    perl -MApache::Session::Postgres -le 'print "@INC";'
    Cheers,
    Rob
      The output of:
      perl -MApache::Session::Postgres -le 'print "@INC"' /opt/m42c/managed/opt/perl/5.8.9/lib/5.8.9/x86_64-linux /opt/m42c/mana +ged/opt/perl/5.8.9/lib/5.8.9 /opt/m42c/managed/opt/perl/5.8.9/lib/sit +e_perl/5.8.9/x86_64-linux /opt/m42c/managed/opt/perl/5.8.9/lib/site_p +erl/5.8.9 .

      As I would expect. Also, using <% Dumper(\@INC) %> from inside of a mason component yeilds the same result; (Since Environments can change).

      Permissions are not the issue, as the webserver runs as the same user as the module installer, (The whole kit is frameworked into /opt/m42c to isolate everything from any system dependencies. This makes things pretty portable, as long as everything is installed in the same place on a different machine. I'm sure you guys have seen this approach many many times.

      Also, I am aware of "require" being far different from "use" and that its use is special.

      And switching to "use" actually does not load the module at all, in fact, it wont even pass tests with use, complaining that $sessionClass has not been declared:

      [amps@autotech M42C-Web]$ make test PERL_DL_NONLAZY=1 "/opt/m42c/managed/opt/perl/5.8.9/bin/perl5.8.9" "-M +ExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness:: +Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t t/M42C-Web.t .. Failed 1/1 subtests Test Summary Report ------------------- t/M42C-Web.t (Wstat: 11 Tests: 0 Failed: 0) Non-zero wait status: 11 Parse errors: Bad plan. You planned 1 tests but ran 0. Files=1, Tests=0, 1 wallclock secs ( 0.02 usr 0.01 sys + 0.04 cusr + 0.02 csys = 0.09 CPU) Result: FAIL Failed 1/1 test programs. 0/0 subtests failed. make: *** [test_dynamic] Error 255
      But that isn't why I chose to use require. I am simply not importing anythi

      ng from Apache::Session::Postgres, why would I not require it? Even still the error I get from "using" the Module is concerning at best. (The line containing the import() was not originally there, and I was just testing something quick.).

      You were correct though, chomp($@) placed the blame on the offending line. - I don't eval {} often from within a module, I tend to do that at the GUI level.

      Also worth noting that installing the module anyway, despite failing make test, throws a seg fault when it's used.

        I think tye has picked it.
        $sessionClass is presumably the string 'Apache::Session::Postgres', but it needs to be the string 'Apache/Session/Postgres.pm'.
        At least, the error message implies that there's a require 'Apache::Session::Postgres' being done somewhere ... and that needs to be changed to require 'Apache/Session/Postgres.pm'

        Cheers,
        Rob
        in: M42C::Web::Session::new end of the sub, should be: return $self, NOT return $class. THAT Fixed a lot of issues. Because I chose to return a string instead of a blessed refrence: $self->{_r}->dir_config->get("M42CSessionClass")

        Had no value, however confused perl may have been I'm fairly sure there should have been an error about calling methods on a non package *anything.

        So there you have it. I feel like an idiot now. :P Thanks for the help though, and I did end up switching to "use" simply because it's easier. I'll consider revising it later XD after testing on a few databases.

      $class->do_something, != $self->do_something. I was absolutely exhausted writing that code, and after some much needed sleep (+ a day at the water park with the fam) + more sleep, i saw the bug strait off and fixed everything up. Much thanks to those that looked over that montage of code.