http://qs321.pair.com?node_id=360444

There is currently no interesting information to see in my scratchpad. But since you dropped by, I didn't want to dissapoint. Check out this most amusing link regarding how to drive: http://fun.from.hell.pl/2002-05-28/naukajazdy.html
#################################################### # Sample Usage (under mod_perl) #################################################### use OpenPlugin(); my $r = shift; my $OP = OpenPlugin->new( config => { src => '/etc/myconf.conf' }, request => { apache => $r } ); my $hair_color = $OP->param->get_incoming('hair'); my $eye_color = $OP->param->get_incoming('eyes'); my $credit_card = $OP->param->get_incoming('credit'); $OP->session->save({ credit => $credit_card }); $OP->httpheader->set_outgoing({ content-type => text/html }); $OP->httpheader->send_outgoing(); print "We got your number!<br>"; #################################################### # Sample Config #################################################### # Portions of OpenPlugin.conf <plugin authenticate> load = Startup driver = DBI datasource = rwcsql </plugin> <plugin param> load = Startup driver = Apache </plugin> <plugin cache> load = Auto driver = File expires = +3h </plugin> # Portions of OpenPlugin-drivermap.conf <drivermap authenticate> DBI = OpenPlugin::Authenticate::DBI Htpasswd = OpenPlugin::Authenticate::Htpasswd LDAP = OpenPlugin::Authenticate::LDAP SMB = OpenPlugin::Authenticate::SMB PAM = OpenPlugin::Authenticate::PAM </drivermap> <drivermap param> Apache = OpenPlugin::Param::Apache CGI = OpenPlugin::Param::CGI </drivermap> <drivermap cache> File = OpenPlugin::Cache::File </drivermap> #################################################### # OpenPlugin Class #################################################### package OpenPlugin; use strict; use vars qw( $AUTOLOAD ); use base qw( Class::Factory ); use OpenPlugin::Plugin qw(); use OpenPlugin::Utility qw(); use Log::Log4perl qw( get_logger ); use constant STATE => '_state'; use constant TOGGLE => '_toggle'; use constant PLUGIN => '_plugin'; use constant PLUGINCONF => '_pluginconf'; use constant INSTANCE => '_instance'; $OpenPlugin::VERSION = '0.06.6'; ########################## # Bootstrap related code # TODO: We should be able to override this by passing in arguments my $log_conf = q( log4perl.rootLogger = WARN, stderr log4perl.appender.stderr = Log::Dispatch::Screen log4perl.appender.stderr.layout = org.apache.log4j.PatternLayout log4perl.appender.stderr.layout.ConversionPattern = %C (%L) %m%n ); Log::Log4perl::init( \$log_conf ); my $logger = get_logger(); # End bootstrap code ######################### sub new { my $pkg = shift; my $params = { @_ }; my $class = ref $pkg || $pkg; my $self = bless( {}, $class ); $self->state("command_line", $params); # Read configuration from file if given $params->{config}{src} ||= $OpenPlugin::Config::Src; if ( $params->{config}{src} ) { $logger->info( "Given config source of [$params->{config}{src} +]" ); $self->load_config( $params ); } # Quit if we haven't been given some sort of config to use unless (( $params->{config}{src} ) || ( $params->{config}{config} +)) { die "No configuration given! You need to pass in the location + ", "to your configuration file, or pass in a hashref containi +ng ", "your configuration data."; } $self->register_plugins; return $self; } ######################################## # Public methods ######################################## # This gets and sets state information for user requests. For instanc +e, we can # maintain the current user and group, whether the user is an administ +rator, # etc. sub state { my ( $self, $key, $value ) = @_; if(( defined $key ) && ( not defined $value )) { $logger->info("Calling state() with key [$key]."); # Just a key passed in, return a single value return $self->{ STATE() }{ $key }; } elsif(( defined $key ) && ( defined $value )) { $logger->info("Calling state() with key [$key] and value [$val +ue]."); # We have a key and value, so assign the value to the key return $self->{ STATE() }{ $key } = $value; } else { $logger->info("Calling state() with no parameters."); # No key or value, return the entire state hash return $self->{ STATE() }; } } # Cleans up the current state in this object and sends a message to # all plugins to cleanup their state as well. sub cleanup { my ( $self ) = @_; $logger->info( "Running cleanup()" ); # Allow plugins to clean up their own state foreach my $plugin ( $self->loaded_plugins ) { $self->$plugin()->cleanup; } # Completely erase all state related information $self->{ STATE() } = {}; # Recreate a hash key for each plugin foreach my $plugin ( $self->loaded_plugins ) { $self->$plugin()->state("Init", 1); } } # This should be called before the object is taken out of scope and # should probably incorporated into a DESTROY() method. sub shutdown { my ( $self ) = @_; $logger->info( "Calling shutdown() from OP" ); $self->cleanup(); # ... do any additional cleanup so we don't have dangling/circular # references, etc.... } ######################################## # Accessor methods ######################################## # Get a list of all plugins which the config plugin knows about sub get_plugins { my $self = shift; return sort keys %{ $self->config->{plugin} }; } # Save any info that we have relating the a plugins configuration sub set_plugin_info { my ( $self, $plugin ) = @_; # $plugin_info contains all the information about a given plugin t +hat was # found in the configuration file my $plugin_info = $self->config->{plugin}{ $plugin }; # We definitely cannot load a plugin without a driver. Warn and s +kip if # that is the case. unless ( ref $plugin_info eq 'HASH' and $plugin_info->{driver} ) { $logger->warn("Invalid driver listed for [$plugin]: ", "[$plugin_info->{driver}]. Skipping." ); } $logger->info( "Driver type found for [$plugin]: ", "[$plugin_info->{driver}]" ); # Store this configuration for whenever we need it $self->{ PLUGINCONF() }{ $plugin } = $plugin_info; } # Get the name of the class name to use for a given driver sub get_plugin_class { my ( $self, $plugin ) = @_; # Get the driver for this plugin, as defined in the config file my $driver = $self->{ PLUGINCONF() }{ $plugin }{driver}; # Get the class name for the driver, as defined in the drivermap f +ile my $plugin_class = $self->config->{drivermap}{ $plugin }{ $driver +}; $logger->info( "Plugin class found for [$plugin]: [$plugin_class]" + ); return $plugin_class; } # Retrieve a list of plugins which are currently loaded, return the va +lue we # received when we called it's load() function earlier sub loaded_plugins { my $self = shift; unless ( ref $self->{ PLUGIN() } eq 'HASH' ) { return (); } return sort keys %{ $self->{ PLUGIN() } }; } # Save the plugin instance (object) that we received by calling its ne +w() # function sub set_plugin_instance { my ( $self, $plugin_type, $instance ) = @_; $self->{ INSTANCE() }{ $plugin_type } = $instance; } ######################################## # Plugin Instanciation ######################################## # Decide how and when to load each plugin sub register_plugins { my $self = shift; foreach my $plugin ( $self->get_plugins ) { $self->set_plugin_info( $plugin ); # These plugins have a "load" time of "Startup", meaning they +are # loaded when the main OpenPlugin module is if( $self->{ PLUGINCONF() }{ $plugin }{ load } eq "Startup" ) +{ unless( OpenPlugin::Plugin->get_factory_map->{$plugin} ) { # Tell OpenPlugin::Plugin that we have a new class tha +t we wish # to load now OpenPlugin::Plugin->add_factory_type( $plugin => $self->get_plugin_class( $plugi +n )); } $self->init_plugin( $plugin ); } # These plugins have a "load" time of "Auto", meaning they are # loaded on demand. If they aren't ever used, they'll never b +e loaded elsif ( $self->{ PLUGINCONF() }{ $plugin }{ load } eq "Auto" ) + { unless( OpenPlugin::Plugin->get_register_map->{$plugin} ) +{ # Tell OpenPlugin::Plugin about a class, so it can lo +ad it if # and when we finally decide to use it OpenPlugin::Plugin->register_factory_type( $plugin => $self->get_plugin_class( $plugi +n )); } } # We need to know how to load a plugin, it doesn't seem approp +riate to # guess. If the configuration isn't correct, give a warning m +essage, # but skip loading it. else { $logger->warn("Invalid load time listed for [$plugin]: [", $self->{ PLUGINCONF() }{ $plugin }{ load }, "]. Skipping." ); } } } # Make a plugin available to programs using us sub init_plugin { my ( $self, $plugin_type ) = @_; # TODO: Eventually, instead of passing the entire command line to +each # plugin, we should just pass items directly related to that plugi +n my $instance = OpenPlugin::Plugin->new( $plugin_type, $self, $self->state->{command_line} ); $self->{ INSTANCE() }{ $plugin_type } = $instance; $self->generate_plugin_method_call( $plugin_type ); $self->{ PLUGIN() }{ $plugin_type } = $self->$plugin_type()->load( +); } # Build a method call for a given plugin sub generate_plugin_method_call { my ( $self, $plugin_type ) = @_; my $class = ref $self; my $method = $class . '::' . $plugin_type; no strict 'refs'; unless ( defined &{ $method } ) { $logger->info("Generating method [$method]"); *{ $method } = sub { my $self = shift; return $self->{ INSTANCE() }{ $plugin_type }; } } } ######################################## # AUTOLOAD # (so great it gets its own section!) ######################################## sub AUTOLOAD { my ( $self, $params ) = @_; my $request = $AUTOLOAD; $request =~ s/.*://; $logger->info( "Autoload request: [$request]\n" ); $self->init_plugin( $request ); $self->$request( $params ); } # Lets not go looking for DESTROY via AUTOLOAD sub DESTROY { } ######################################## # CONFIGURATION ######################################## # Configuration is different from other plugins because of the bootstr +apping # issue. sub load_config { my ( $self, $params ) = @_; unless( OpenPlugin::Plugin->get_factory_map->{config} ) { OpenPlugin::Plugin->add_factory_type( config => 'OpenPlugin::Config' ); } my $config = OpenPlugin::Plugin->new( 'config', $self, $params->{c +onfig} ); $self->set_plugin_instance( "config", $config->read ); $self->generate_plugin_method_call( "config" ); } 1; __END__ =head1 NAME OpenPlugin - Plugin manager for web applications =head1 SYNOPSIS use OpenPlugin(); my $r = shift; my $OP = OpenPlugin->new( config => { src => '/etc/myconf.conf' +}, request => { apache => $r } ); my $is_authenticated = $OP->authenticate->authenticate({ username => + 'badguy', password => + 'scylla' }); unless ( $is_authenticated ) { $OP->exception->throw( "Login incorrect!" ); } $session = $OP->session->fetch( $session_id ); $session->{ 'hair' } = $OP->param->get_incoming( 'hair' ); $session->{ 'eyes' } = $OP->param->get_incoming( 'eyes' ); $OP->session->save( $session ); $OP->httpheader->send_outgoing(); print "You have $session->{'hair'} hair and $session->{'eyes'} eyes< +br>"; =head1 DESCRIPTION OpenPlugin is an architecture which manages plugins for web applicatio +ns. It allows you to incorporate any number of plugins and drivers into your +web application, offering a powerful user environment. OpenPlugin comes with numerous plugins, including Session Support, Use +r Authentication, Datasource Management, and Logging. With OpenPlugin's + driver support, you can do things like change your logging facility from STDE +RR to Syslog by changing one line in a config file. OpenPlugin also offers plugins which abstract Apache::Request and CGI, + allowing you to switch between the two by only changing a setting in a config f +ile. Each plugin is written in a way to allow any number of drivers which c +an manipulate how the plugin functions, or where it can find it's data. =head1 BACKGROUND Currently, there are a number of web application frameworks available. And while each one is unique, there is a certain amount of functionali +ty that each shares. Often, that functionality is built in to the particular framework, instead of being a seperate component.ÜÜ OpenPlugin offers this functionality that is common between frameworks +, but it is designed to be a reusable component, which can be used within any f +ramework or standalone web application. This allows OpenPlugin to grow beyond +the abilities of any one developer, and beyond the scope of any one framew +ork. OpenPlugin has developed into a powerful architecture allowing for ext +ensible applications. =head1 FUNCTIONS While the main OpenPlugin class does provide some publicaly available functions, you'll find the majority of OpenPlugin's funcionality in it +'s plugins. =over 4 =item B<$OP = OpenPlugin->new( %params )> You can pass a number of parameters into the B<new()> method. Each of + those parameters can effect how a given plugin, or OpenPlugin as a whole, fu +nctions. The parameters in %params will be available to each plugin as they are loaded. The syntax for the %params hash is: %params = qw( plugin_name => { plugin_param => plugin_value }, other_plugin => { plugin_param => plugin_value }, For example: %params = qw( config => { src => /path/to/config.conf }, request => { apache => $r }, ); This returns an OpenPlugin object. =item B<state( [ key ], [ value ] )> This function is for storing and retrieving state information. This information is destroyed when the script exits (see the L<Session|OpenPlugin::Session> and L<Cache|OpenPlugin::Cache> plugins for storing information across requests). This returns the full state hash if passed no parameters, a value if p +assed one parameter (a key), or sets a key equal to a given value if sent two pa +rameters. =item B<cleanup()> This function tells the main OpenPlugin module, and all of it's plugin +s, to perform a "cleanup". This is typically called by you when your applic +ation is exiting, perhaps even from a DESTROY() method. This is important when + running under mod_perl, as it clears out all the state information created dur +ing the current request. If not cleared out, mod_perl will happily keep this information for the next request too -- this is not what you want! Be + sure to run cleanup() at the end of your application. If you are using L<Open +Thought>, OpenThought does call this method for you. =back =head1 PLUGINS The API for individual plugins is available by looking at that particu +lar plugin's documentation. The following plugins are available: =over 4 =item * L<Application|OpenPlugin::Application> =item * L<Authentication|OpenPlugin::Authentication> =item * L<Cache|OpenPlugin::Cache> =item * L<Config|OpenPlugin::Config> =item * L<Cookie|OpenPlugin::Cookie> =item * L<Datasource|OpenPlugin::Datasource> =item * L<Exception|OpenPlugin::Exception> =item * L<Httpheader|OpenPlugin::Httpheader> =item * L<Log|OpenPlugin::Log> =item * L<Param|OpenPlugin::Param> =item * L<Session|OpenPlugin::Session> =item * L<Upload|OpenPlugin::Upload> =back Many of these plugins accept parameters passed into OpenPlugin's B<new +()> constructor, and a few even require it. You can obtain a list of what parameters a plugin recognizes by reading the documentation for the pl +ugin and driver which you are using. Generally speaking, the documentation for + a plugin shows how to program it's interface, and the documentation for the dri +ver shows how to configure it, along with what parameters you can pass into it. =head1 TO DO All kinds of stuff! This module has plenty of room for improvement. +The API is not complete. See the TO DO list for the individual plugins to see + a few of the ideas that I've written down. There's also plenty of room for more documentation. =head1 COPYRIGHT Copyright (c) 2001-2002 Eric Andreychek. All rights reserved. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 AUTHORS Eric Andreychek <eric@openthought.net> =head1 CONTRIBUTORS Chris Winters initially helped get things rolling. OpenPlugin also ma +kes use of his Class::Factory module, and I occasionally borrow code from OpenInteract/SPOPS. =head1 SEE ALSO Web applications which make use of OpenPlugin: =over 4 =item * L<OpenThought|OpenThought> =back =cut