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
|