cvsuser     01/12/05 14:45:05

  Modified:    P5EEx/Blue MANIFEST
               P5EEx/Blue/P5EEx/Blue Config.pm Config.pod Context.pm
                        Exceptions.pm Messaging.pm P5EE.pm Procedure.pm
                        Repository.pm Security.pm Serializer.pm Service.pm
                        Session.pm Widget.pm
               P5EEx/Blue/examples Config.1
               P5EEx/Blue/sbin perldocs
  Added:       P5EEx/Blue/P5EEx/Blue LogChannel.pm Template.pm
               P5EEx/Blue/P5EEx/Blue/Config File.pm
               P5EEx/Blue/P5EEx/Blue/Serializer Storable.pm XMLSimple.pm
               P5EEx/Blue/examples Reference.1 config.ini config.properties
                        config.xml
  Removed:     P5EEx/Blue/P5EEx/Blue Log.pm Templates.pm
  Log:
  Got Config working with Serializer. Changed Templates to Template. Added Exceptions 
and tests.
  
  Revision  Changes    Path
  1.4       +35 -5     p5ee/P5EEx/Blue/MANIFEST
  
  Index: MANIFEST
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/MANIFEST,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -w -r1.3 -r1.4
  --- MANIFEST  2001/11/22 05:16:58     1.3
  +++ MANIFEST  2001/12/05 22:45:03     1.4
  @@ -1,12 +1,42 @@
  -CHANGES
  -MANIFEST
   Makefile.PL
   README
   TODO
  -P5EEx/Blue/perlstyle.pod
  -P5EEx/Blue/podstyle.pod
  +CHANGES
  +MANIFEST
   P5EEx/Blue/P5EE.pm
  +P5EEx/Blue/Exceptions.pm
  +P5EEx/Blue/Reference.pm
   P5EEx/Blue/Config.pm
  +P5EEx/Blue/Config.pod
  +P5EEx/Blue/Config/File.pm
  +P5EEx/Blue/Config/File.pod
   P5EEx/Blue/Context.pm
   P5EEx/Blue/Context/CGI.pm
  -P5EEx/Blue/Config/XML.pm
  +P5EEx/Blue/Service.pm
  +P5EEx/Blue/Serializer.pm
  +P5EEx/Blue/Serializer/XMLSimple.pm
  +P5EEx/Blue/Serializer/Ini.pm
  +P5EEx/Blue/Serializer/Properties.pm
  +P5EEx/Blue/Session.pm
  +P5EEx/Blue/Security.pm
  +P5EEx/Blue/Repository.pm
  +P5EEx/Blue/Template.pm
  +P5EEx/Blue/Widget.pm
  +P5EEx/Blue/Messaging.pm
  +P5EEx/Blue/Procedure.pm
  +P5EEx/Blue/LogChannel.pm
  +P5EEx/Blue/datetime.pod
  +P5EEx/Blue/perlstyle.pod
  +P5EEx/Blue/podstyle.pod
  +sbin/perldocs
  +htdocs/api/perldocs.css
  +htdocs/style.css
  +htdocs/images/logo.gif
  +examples/Config.1
  +examples/Config.1.out
  +examples/config.ini
  +examples/config.pl
  +examples/config.xml
  +examples/Reference.1
  +examples/Reference.1.out
  +t/Config.t
  
  
  
  1.4       +7 -90     p5ee/P5EEx/Blue/P5EEx/Blue/Config.pm
  
  Index: Config.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Config.pm,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -w -r1.3 -r1.4
  --- Config.pm 2001/11/22 05:16:59     1.3
  +++ Config.pm 2001/12/05 22:45:03     1.4
  @@ -1,101 +1,18 @@
   
   #############################################################################
  -## $Id: Config.pm,v 1.3 2001/11/22 05:16:59 spadkins Exp $
  +## $Id: Config.pm,v 1.4 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Config;
  -$VERSION = do { my @r=(q$Revision: 1.3 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r};
  +$VERSION = do { my @r=(q$Revision: 1.4 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r};
   
  -use strict;
  -
  -# NOTE: The pod material has been separated out to Config.pod because
  -#       MakeMaker ignores files matching /(config|setup).*.pm/
  -
  -sub new {
  -    my $this = shift;
  -    my $class = ref($this) || $this;
  -
  -    my ($name, $args, $i);
  -    if ($#_ == -1) {
  -        $args = {};
  -        $name = "default";
  -    }
  -    else {
  -        if (ref($_[0]) eq "HASH") {
  -            $args = shift;
  -            $name = shift if ($#_ % 2 == 0);
  -            for ($i = 0; $i < $#_; $i++) {
  -                $args->{$_[$i]} = $_[$i+1];
  -            }
  -        }
  -        else {
  -            $name = shift if ($#_ % 2 == 0);
  -            $args = ($#_ > -1) ? { @_ } : {};
  -        }
  -        $name = $args->{name} if (!$name);
  -        $name = "default" if (!$name);
  -    }
  -
  -    # bootstrap phase: bless an empty hash
  -    my $self = {};
  -    bless $self, $class;
  -
  -    # load phase: replace empty hash with loaded hash, bless again
  -    $self = $self->load($args);
  -    bless $self, $class;
  -
  -    $self->init($args);  # allows a subclass to override this portion
  +use P5EEx::Blue::P5EE;
  +use P5EEx::Blue::Reference;
  +@ISA = ( "P5EEx::Blue::Reference" );
   
  -    return $self;
  -}
  -
  -sub init {
  -    my $self = shift;
  -}
  -
  -sub load {
  -    my ($self, $args) = @_;
  -    local(*FILE);
  -
  -    my ($file, @perl, $perl, $conf, $open);
  -    if (defined $args && $args->{configFile}) {
  -        $file = $args->{configFile};
  -        $open = open(main::FILE,"< $file");
  -    }
  -    else {
  -        $file = $0;
  -        $file =~ s!\.[^/]*$!!;
  -        $file .= ".pl";
  -        $open = open(main::FILE,"< $file");
  -        $open = open(main::FILE,"< config.pl") if (!$open);
  -    }
  -
  -    $conf = {};
  -    if ($open) {
  -        @perl = <main::FILE>;
  -        close(main::FILE);
  -        $perl = join("",@perl);
  -        if ($perl =~ /^\$[a-zA-Z][a-zA-Z0-9_]* *= *(\{.*\};[ \n]*)$/s) {
  -            $perl = "\$conf = $1";   # untainted now
  -            eval($perl);
  -            P5EEx::Blue::Exception::Config->throw( error => $@ );
  -        }
  -        else {
  -            P5EEx::Blue::Exception::Config->throw( error => 
  -                "Data didn't have \"\$var = {...};\" format." );
  -        }
  -    }
  -    $conf;
  -}
  -
  -use Data::Dumper;
  +use strict;
   
  -sub dump {
  -    my ($self) = @_;
  -    my $d = Data::Dumper->new([ $self ], [ "conf" ]);
  -    $d->Indent(1);
  -    return $d->Dump();
  -}
  +# there are no methods for this class yet
   
   1;
   
  
  
  
  1.4       +4 -4      p5ee/P5EEx/Blue/P5EEx/Blue/Config.pod
  
  Index: Config.pod
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Config.pod,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -w -r1.3 -r1.4
  --- Config.pod        2001/11/30 16:00:52     1.3
  +++ Config.pod        2001/12/05 22:45:03     1.4
  @@ -1,6 +1,6 @@
   
   ######################################################################
  -## $Id: Config.pod,v 1.3 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Config.pod,v 1.4 2001/12/05 22:45:03 spadkins Exp $
   ######################################################################
   
   =head1 NAME
  @@ -32,7 +32,7 @@
      $config->{Config}{default}   # config settings for the default Config service
      $config->{Security}          # config settings for all Security services
      $config->{Security}{default} # config settings for the default Security service
  -   $config->{Templates}{tt}     # config settings for the Templates service named 
"tt"
  +   $config->{Template}{tt}      # config settings for the Template service named 
"tt"
   
      # The default driver (if "configClass" not supplied) reads in a Perl
      # data structure from the file.  Alternate drivers can read a Storable,
  @@ -100,7 +100,7 @@
   
   =back
   
  -=head2 Class Group Requirements
  +=head2 Requirements
   
   The following are enumerated requirements for the Config Class Group.
   It forms a high-level feature list. 
  @@ -136,7 +136,7 @@
    * Throws: P5EEx::Blue::Exception::Config
    * Since:  0.01
   
  -=head2 Class Design
  +=head2 Design
   
   The P5EEx::Blue::Config class is a very thin code wrapper around a perl
   data structure.  Although they could access the data directly through 
  
  
  
  1.5       +5 -5      p5ee/P5EEx/Blue/P5EEx/Blue/Context.pm
  
  Index: Context.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Context.pm,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -w -r1.4 -r1.5
  --- Context.pm        2001/11/30 16:00:52     1.4
  +++ Context.pm        2001/12/05 22:45:03     1.5
  @@ -1,6 +1,6 @@
   
   #############################################################################
  -## $Id: Context.pm,v 1.4 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Context.pm,v 1.5 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Context;
  @@ -23,7 +23,7 @@
      # any of the following named parameters may be specified
      $context = P5EEx::Blue::P5EE->context(
          contextClass => "P5EEx::Blue::Context::CGI",
  -       configClass => "P5EEx::Blue::Config::XML",   # or any Config args
  +       configClass => "P5EEx::Blue::Config::File",   # or any Config args
      );
   
      # ... alternative way (used internally) ...
  @@ -151,7 +151,7 @@
       $context = P5EEx::Blue::Context->new();
       $context = P5EEx::Blue::Context->new(
           contextClass => 'P5EEx::Blue::Context::CGI',
  -        configClass  => 'P5EEx::Blue::Config::XML',
  +        configClass  => 'P5EEx::Blue::Config::File',
           configFile   => 'config.xml',
       );
   
  @@ -188,7 +188,7 @@
   
       $config_class   = $args->{configClass};
       $config_class   = $ENV{P5EE_CONFIG_CLASS} if (! $config_class);
  -    $config_class   = "P5EEx::Blue::Config" if (! $config_class);
  +    $config_class   = "P5EEx::Blue::Config::File" if (! $config_class);
   
       $self->{config} = P5EEx::Blue::P5EE->new($config_class, "new", $args);
   
  @@ -250,7 +250,7 @@
   =head2 log()
   
   The log() method writes a string (the concatenated list of @args) to
  -a log file.
  +the default log channel.
   
       * Signature: $context->log(@args);
       * Param:  @args        string  [in]
  
  
  
  1.3       +79 -7     p5ee/P5EEx/Blue/P5EEx/Blue/Exceptions.pm
  
  Index: Exceptions.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Exceptions.pm,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- Exceptions.pm     2001/11/30 16:00:52     1.2
  +++ Exceptions.pm     2001/12/05 22:45:03     1.3
  @@ -8,38 +8,78 @@
   use strict;
   use vars qw($VERSION);
   
  -$VERSION = sprintf '%2d.%02d', q$Revision: 1.2 $ =~ /(\d+)\.(\d+)/;
  +$VERSION = sprintf '%2d.%02d', q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/;
   
   my %e;
   
   BEGIN {
       %e = (
           'P5EEx::Blue::Exception' => {
  -            description => 'An error occurred in P5EE.',
  +            description => 'An exception in a core P5EE class.',
           },
   
           'P5EEx::Blue::Exception::Context' => {
  -            description => 'An error occurred in the Context.',
  +            description => 'An exception in the Context service.',
               isa => 'P5EEx::Blue::Exception',
           },
   
           'P5EEx::Blue::Exception::Config' => {
  -            description => 'An error occurred in the Config.',
  +            description => 'An exception in the Config service.',
               isa => 'P5EEx::Blue::Exception',
           },
   
           'P5EEx::Blue::Exception::Serializer' => {
  -            description => 'An error occurred in the Serializer.',
  +            description => 'An exception in the Serializer service.',
               isa => 'P5EEx::Blue::Exception',
           },
   
  +        'P5EEx::Blue::Exception::Repository' => {
  +            description => 'An exception in the Repository service.',
  +            isa => 'P5EEx::Blue::Exception',
  +        },
  +
  +        'P5EEx::Blue::Exception::Security' => {
  +            description => 'An exception in the Security service.',
  +            isa => 'P5EEx::Blue::Exception',
  +        },
  +
  +        'P5EEx::Blue::Exception::Session' => {
  +            description => 'An exception in the Session service.',
  +            isa => 'P5EEx::Blue::Exception',
  +        },
  +
  +        'P5EEx::Blue::Exception::Widget' => {
  +            description => 'An exception in the Widget service.',
  +            isa => 'P5EEx::Blue::Exception',
  +        },
  +
  +        'P5EEx::Blue::Exception::Template' => {
  +            description => 'An exception in the Template service.',
  +            isa => 'P5EEx::Blue::Exception',
  +        },
  +
  +        'P5EEx::Blue::Exception::Procedure' => {
  +            description => 'An exception in the Procedure service.',
  +            isa => 'P5EEx::Blue::Exception',
  +        },
  +
  +        'P5EEx::Blue::Exception::Messaging' => {
  +            description => 'An exception in the Messaging service.',
  +            isa => 'P5EEx::Blue::Exception',
  +        },
  +
  +        'P5EEx::Blue::Exception::LogChannel' => {
  +            description => 'An exception in the LogChannel service.',
  +            isa => 'P5EEx::Blue::Exception',
  +        },
  +
       );
   }
   
   use Exception::Class (%e);
   
  -if ($ENV{P5EE_DEBUG})
  -{
  +#if ($ENV{P5EE_DEBUG})
  +if (1) {
       Exception::Class::Base->do_trace(1);
       foreach my $class (keys %e) {
           $class->do_trace(1);
  @@ -96,6 +136,38 @@
   =item * P5EEx::Blue::Exception::Serializer
   
   Base class for all Serializer-related exceptions.
  +
  +=item * P5EEx::Blue::Exception::Repository
  +
  +Base class for all Repository-related exceptions.
  +
  +=item * P5EEx::Blue::Exception::Security
  +
  +Base class for all Security-related exceptions.
  +
  +=item * P5EEx::Blue::Exception::Session
  +
  +Base class for all Session-related exceptions.
  +
  +=item * P5EEx::Blue::Exception::Widget
  +
  +Base class for all Widget-related exceptions.
  +
  +=item * P5EEx::Blue::Exception::Template
  +
  +Base class for all Template-related exceptions.
  +
  +=item * P5EEx::Blue::Exception::Procedure
  +
  +Base class for all Procedure-related exceptions.
  +
  +=item * P5EEx::Blue::Exception::Messaging
  +
  +Base class for all Messaging-related exceptions.
  +
  +=item * P5EEx::Blue::Exception::LogChannel
  +
  +Base class for all LogChannel-related exceptions.
   
   =back
   
  
  
  
  1.3       +2 -1      p5ee/P5EEx/Blue/P5EEx/Blue/Messaging.pm
  
  Index: Messaging.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Messaging.pm,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- Messaging.pm      2001/11/30 16:00:52     1.2
  +++ Messaging.pm      2001/12/05 22:45:03     1.3
  @@ -1,10 +1,11 @@
   
   #############################################################################
  -## $Id: Messaging.pm,v 1.2 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Messaging.pm,v 1.3 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Messaging;
   
  +use P5EEx::Blue::P5EE;
   use P5EEx::Blue::Service;
   @ISA = ( "P5EEx::Blue::Service" );
   
  
  
  
  1.5       +19 -15    p5ee/P5EEx/Blue/P5EEx/Blue/P5EE.pm
  
  Index: P5EE.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/P5EE.pm,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -w -r1.4 -r1.5
  --- P5EE.pm   2001/11/30 16:00:52     1.4
  +++ P5EE.pm   2001/12/05 22:45:03     1.5
  @@ -1,6 +1,6 @@
   
   #############################################################################
  -## $Id: P5EE.pm,v 1.4 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: P5EE.pm,v 1.5 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::P5EE;
  @@ -116,7 +116,7 @@
   =item * Class Group: L<C<Session>|P5EEx::Blue::Session>
         - represents the state associated with a sequence of multiple events
   
  -=item * Class Group: L<C<Templates>|P5EEx::Blue::Templates>
  +=item * Class Group: L<C<Template>|P5EEx::Blue::Template>
         - encapsulates template system details
   
   =item * Class Group: L<C<Procedure>|P5EEx::Blue::Procedure>
  @@ -134,8 +134,8 @@
   =item * Class Group: L<C<Security>|P5EEx::Blue::Security>
         - provides authentication and authorization
   
  -=item * Class Group: L<C<Log>|P5EEx::Blue::Log>
  -      - a logging service
  +=item * Class Group: L<C<LogChannel>|P5EEx::Blue::LogChannel>
  +      - a logging channel through which messages may be logged
   
   =back
   
  @@ -153,6 +153,10 @@
   
   =item * Class: L<C<P5EEx::Blue::P5EE>|"Class: P5EEx::Blue::P5EE">
   
  +=item * Class: L<C<P5EEx::Blue::Reference>|P5EEx::Blue::Exceptions>
  +
  +=item * Class: L<C<P5EEx::Blue::Reference>|P5EEx::Blue::Reference>
  +
   =item * Class: L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service>
   
   =item * Document: L<C<Perlstyle, Perl Style Guide>|P5EEx::Blue::perlstyle>
  @@ -323,23 +327,23 @@
       return ($context{$name}) if (defined $context{$name});
       
       if (! $args->{contextClass}) {
  -        if (defined $ENV{"P5EE_CONTEXT_CLASS"}) {     # env variable set?
  -            $args->{contextClass} = $ENV{"P5EE_CONTEXT_CLASS"};
  +        if (defined $ENV{P5EE_CONTEXT_CLASS}) {     # env variable set?
  +            $args->{contextClass} = $ENV{P5EE_CONTEXT_CLASS};
           }
           else {   # try autodetection ...
  -            my $gateway = $ENV{"GATEWAY_INTERFACE"};
  -            if (defined $gateway && $gateway =~ /CGI-Perl/) {  # running under 
mod_perl?
  +            my $gateway = $ENV{GATEWAY_INTERFACE};
  +            if (defined $gateway && $gateway =~ /CGI-Perl/) {  # mod_perl?
                   $args->{contextClass} = "P5EEx::Blue::Context::Modperl";
               }
  -            elsif ($ENV{"HTTP_USER_AGENT"}) {  # running as CGI script?
  +            elsif ($ENV{HTTP_USER_AGENT}) {  # running as CGI script?
                   $args->{contextClass} = "P5EEx::Blue::Context::CGI";
               }
  -            # let's be real... these next two are not really critical right now
  -            #elsif ($ENV{"DISPLAY"}) {         # running with an X DISPLAY var set?
  -            #    $args->{context} = "P5EEx::Blue::Context::Gtk";
  +            # let's be real... these next two are not critical right now
  +            #elsif ($ENV{DISPLAY}) { # running with an X DISPLAY var set?
  +            #    $args->{contextClass} = "P5EEx::Blue::Context::Gtk";
               #}
  -            #elsif ($ENV{"TERM"}) {            # running with a TERM var to support 
Curses?
  -            #    $args->{context} = "P5EEx::Blue::Context::Curses";
  +            #elsif ($ENV{TERM}) { # running with a TERM var for Curses?
  +            #    $args->{contextClass} = "P5EEx::Blue::Context::Curses";
               #}
               else {                             # fall back to CGI, because it works 
OK in command mode
                   $args->{contextClass} = "P5EEx::Blue::Context::CGI";
  
  
  
  1.2       +2 -1      p5ee/P5EEx/Blue/P5EEx/Blue/Procedure.pm
  
  Index: Procedure.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Procedure.pm,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -w -r1.1 -r1.2
  --- Procedure.pm      2001/11/30 16:00:52     1.1
  +++ Procedure.pm      2001/12/05 22:45:03     1.2
  @@ -1,10 +1,11 @@
   
   #############################################################################
  -## $Id: Procedure.pm,v 1.1 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Procedure.pm,v 1.2 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Procedure;
   
  +use P5EEx::Blue::P5EE;
   use P5EEx::Blue::Service;
   @ISA = ( "P5EEx::Blue::Service" );
   
  
  
  
  1.3       +850 -3    p5ee/P5EEx/Blue/P5EEx/Blue/Repository.pm
  
  Index: Repository.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Repository.pm,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- Repository.pm     2001/11/30 16:00:52     1.2
  +++ Repository.pm     2001/12/05 22:45:03     1.3
  @@ -1,10 +1,11 @@
   
   #############################################################################
  -## $Id: Repository.pm,v 1.2 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Repository.pm,v 1.3 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Repository;
   
  +use P5EEx::Blue::P5EE;
   use P5EEx::Blue::Service;
   @ISA = ( "P5EEx::Blue::Service" );
   
  @@ -16,13 +17,102 @@
   
   =head1 SYNOPSIS
   
  -    use P5EEx::Blue::P5EE;
  +    use P5EEx::Blue::Repository;
   
       $context = P5EEx::Blue::P5EE->context();
       $repository = $context->service("Repository");  # or ...
       $repository = $context->repository();
   
  -    ... TBD ...
  +    $rep = Repository::Base->new();        # looks for %ENV, then config file
  +    $rep = Repository::Base->new("sysdb"); # looks for %ENV, then config file using 
"sysdb"
  +    $rep2 = $rep->new();                              # copies attributes of 
existing $rep
  +    $rep = Repository::Base->new(@positional_args);   # undefined for 
Repository::Base
  +    $config = {
  +      'repository' => {
  +        'db' => {
  +          'arg1' => 'value1',
  +          'arg2' => 'value2',
  +        },
  +        'rep2' => {
  +          'arg1' => 'value1',
  +          'arg2' => 'value2',
  +        },
  +      },
  +    };
  +    $rep = Repository::Base->new($config);
  +    $rep = Repository::Base->new("rep2",$config);
  +
  +    ###################################################################
  +    # The following methods are needed for SQL support
  +    ###################################################################
  +
  +    $ok = $rep->connect();         # initialize repository (will happen 
automatically in constructor)
  +    $ok = $rep->disconnect();      # cleanup repository (will happen automatically 
in destructor)
  +    $rep->is_connected();          # returns 1 if connected (ready for use), 0 if 
not
  +    $errmsg = $rep->error();       # returns the error string for prev op ("" if no 
error)
  +    $numrows = $rep->numrows();    # returns the number of rows affected by prev op
  +    print $rep->error(), "\n" if (!$rep->connect());
  +    print $rep->error(), "\n" if ($rep->connect() != $rep->OK);
  +
  +    # DATA TYPE HELPER METHODS
  +    $repdate = $rep->format_repdate($date_string);   # free-form date string as 
entered by a person
  + 
  +    # META-DATA: (about the tables)
  +    $rep->load_rep_metadata();
  +    $rep->load_table_metadata($tablename);
  +    $typenames    = $rep->get_type_names();                        # print 
"@$typenames\n";
  +    $typelabels   = $rep->get_type_labels();                       # print 
"%$typelabels\n";
  +    $typedef      = $rep->get_type_def($typename);                 # print 
"%$type\n";
  +    $tablenames   = $rep->get_table_names();                       # print 
"@$tablenames\n";
  +    $tablelabels  = $rep->get_table_labels();                      # print 
"%$tablelabels\n";
  +    $tabledef     = $rep->get_table_def($tablename);               # print 
"%$table\n";
  +    $columnnames  = $rep->get_column_names($tablename);            # print 
"@$columnnames\n";
  +    $columnlabels = $rep->get_column_labels($tablename);           # print 
"%$columnlabels\n";
  +    $columndef    = $rep->get_column_def($tablename,$columnname);  # print 
"%$column\n";
  +
  +    # MEDIUM-LEVEL
  +    $row       = $rep->select_row ($table, \@cols,              \@params, 
\%paramvalues);
  +    $rows      = $rep->select_rows($table, \@cols,              \@params, 
\%paramvalues, \@ordercols, $startrow, $endrow);
  +    $ok        = $rep->insert_row ($table, \@cols, \@colvalues);
  +    $ok        = $rep->insert_rows($table, \@cols, \@rows);
  +    $ok        = $rep->update_row ($table, \@cols, \@colvalues, \@keycolidx);
  +    $ok        = $rep->update_rows($table, \@cols, \@colvalues, \@params, 
\%paramvalues);
  +    $ok        = $rep->store_row  ($table, \@cols, \@colvalues, \@keycolidx, 
$update_first);
  +    $ok        = $rep->store_rows ($table, \@cols, \@rows,      \@keycolidx, 
$update_first);
  +    $ok        = $rep->delete_row ($table, \@cols, \@colvalues, \@keycolidx);
  +    $ok        = $rep->delete_rows($table,                      \@params, 
\%paramvalues);
  +
  +    # HIGH-LEVEL (CACHED)
  +
  +    @keys   = $rep->get_keys($table, \%paramvalues);
  +    @keys   = $rep->get_related_keys($table, $key, $related_table, $relation);
  + 
  +    @values = $rep->get_values($table, $key, \@cols);
  +    $value  = $rep->get_value ($table, $key, "first_name");
  + 
  +    $key = $rep->set_values($table, $key, \@cols, \@values);
  +    $key = $rep->set_value ($table, $key, "first_name", $value);
  + 
  +    $rows = $rep->get_rows($table, undef, \%paramvalues);
  +    $rows = $rep->get_rows($table, \@cols, \%paramvalues);
  +    $rows = $rep->get_rows($table, \@cols, \%paramvalues, \@keys);
  +    $row  = $rep->get_row ($table, $key);
  +    @idx  = $rep->get_column_idx($table, \@cols);
  +    ($key, $first_name, $last_name) = @{$row}[@idx];
  + 
  +    $rep->add_columns_fetched   ($table, \@cols);
  +    $rep->add_columns_fetched   ($table, \@cols, \@colidx);
  +    $rep->set_row_hint      ($table, \%paramvalues);
  +    $rep->clear_columns_fetched ($table);
  +    $rep->clear_row_hint    ($table);
  +    @columns = $rep->get_required_columns($table);
  +
  +    $rep->load_cache();
  +    $rep->clear_cache();
  +    $rep->commit();
  +    $rep->rollback();
  +
  +=cut
   
   =head1 DESCRIPTION
   
  @@ -126,6 +216,763 @@
   
   sub tbd {
       my ($self) = @_;
  +}
  +
  +#############################################################################
  +# CONSTANTS
  +#############################################################################
  +
  +sub OK { 1; }
  +
  +#############################################################################
  +# ATTRIBUTES
  +#############################################################################
  +
  +# BASIC
  +# $self->{name}       # name of this repository (often "db")
  +# $self->{config}     # hash of config file data
  +
  +# CURRENT STATE
  +# $self->{error}      # most recent error generated from this module
  +# $self->{numrows}
  +
  +# METADATA - Database Types
  +# $self->{types}
  +# $self->{type}{$type}
  +# $self->{type}{$typenum}
  +# $self->{type}{$type}{type_name}
  +# $self->{type}{$type}{data_type}
  +# $self->{type}{$type}{column_size}
  +# $self->{type}{$type}{literal_prefix}
  +# $self->{type}{$type}{literal_suffix}
  +# $self->{type}{$type}{unsigned_attribute}
  +# $self->{type}{$type}{auto_unique_value}
  +# $self->{type}{$type}{quoted}
  +
  +# METADATA - Tables and Columns
  +# $self->{tables}
  +# $self->{table}{$table}{readonly}
  +# $self->{table}{$table}{columns}
  +# $self->{table}{$table}{column}{$column}
  +# $self->{table}{$table}{column}{$column}{name}
  +# $self->{table}{$table}{column}{$column}{type_name}
  +# $self->{table}{$table}{column}{$column}{type}
  +# $self->{table}{$table}{column}{$column}{notnull}
  +# $self->{table}{$table}{column}{$column}{quoted}
  +
  +#############################################################################
  +# CONSTRUCTOR
  +#############################################################################
  +
  +# $rep = Repository::Base->new();
  +
  +sub new {
  +    my $this = shift;
  +    my ($class, $self);
  +    $self = {};
  +
  +    # contructing a new object from scratch from the class
  +    # i.e. $rep = Repository::Base->new(...);
  +    if (ref($this) eq "") {
  +        $class = $this;       # must be a scalar, presumably a class name
  +        bless $self, $class;
  +        $self->init_base(@_);
  +    }
  +    # contructing a new object from another object
  +    # $rep = $rep1->new();
  +    else {
  +        $class = ref($this);
  +        bless $self, $class;
  +        $self->init_base($this->{name},$this->{config});
  +    }
  +
  +    $self->init();
  +
  +    if (!$self->connect()) {
  +        my ($repname, $repconfig);
  +        $repconfig = $self->{repconfig};
  +
  +        print STDERR "Error on connect():";
  +        foreach (keys %$repconfig) {
  +            print STDERR " $_=[", $repconfig->{$_}, "]";
  +        }
  +        print STDERR "\n";
  +        return(undef);
  +    }
  +
  +    $self->load_rep_metadata();
  +
  +    return $self;
  +}
  +
  +#####################################################################
  +# init_base()
  +# initialize the {config} structure and the {name} attribute
  +#####################################################################
  +sub init_base {
  +    my $self = shift;
  +    my ($dbidriver, $dbname, $dbuser, $dbpass, $dbioptions, $dbschema);
  +    my ($repname, $config, $repconfig);
  +
  +    # $rep = Repository::Base->new();                # looks for %ENV, then config 
file
  +    # $rep = Repository::Base->new($config);         # a MySQL database named 
"mydb" (the default)
  +    # $rep = Repository::Base->new("sysdb");         # looks for %ENV, then config 
file using "sysdb"
  +    # $rep = Repository::Base->new("sysdb",$config); # an Oracle database named 
"SYSDB"
  +
  +    if ($#_ == -1) {
  +        $repname = "db";
  +        $config  = Repository->read_config();
  +    }
  +    elsif ($#_ == 0 && ref($_[0]) eq "") {
  +        $repname = shift;
  +        $config  = Repository->read_config();
  +    }
  +    elsif ($#_ == 0 && (ref($_[0]) eq "HASH" || ref($_[0]) =~ /^Widget::/)) {
  +        $repname = "db";
  +        $config  = shift;
  +    }
  +    elsif ($#_ == 1 && (ref($_[1]) eq "HASH" || ref($_[1]) =~ /^Widget::/)) {
  +        $repname = shift;
  +        $config  = shift;
  +    }
  +    else {
  +        $repname = "db";
  +        $config  = $self->make_config(@_);
  +    }
  +
  +    $self->{name}    = $repname;
  +    $self->{config}  = $config;
  +
  +    $self->{numrows} = 0;
  +    $self->{error}   = "";
  +
  +    $repconfig = $config->{repository}{$repname};
  +    if (!$repconfig || ref($repconfig) ne "HASH") {
  +        print STDERR "Error: config does not have an entry for the $repname 
repository (\$conf->{repository}{$repname})\n";
  +        return(undef);
  +    }
  +    $self->{repconfig} = $repconfig;
  +}
  +
  +sub init { }         # OVERRIDE IN SUBCLASS
  +
  +sub DESTROY {
  +    my $self = shift;
  +    $self->disconnect();
  +}
  +
  +#############################################################################
  +# CONFIG METHODS
  +#############################################################################
  +
  +sub make_config {    # OVERRIDE IN SUBCLASS
  +    my $conf = {
  +      'repository' => {
  +        'db' => {
  +         },
  +       },
  +    };
  +    $conf;
  +}
  +
  +sub read_config {
  +    my ($self, $file) = @_;
  +    return Repository->read_config($file);
  +}
  +
  +#############################################################################
  +# METHODS
  +#############################################################################
  +
  +sub connect { 1; }        # OVERRIDE IN SUBCLASS
  +sub disconnect { 1; }     # OVERRIDE IN SUBCLASS
  +sub is_connected { 1; }   # OVERRIDE IN SUBCLASS
  +
  +sub error {               # OVERRIDE IN SUBCLASS
  +    my $err = $_[0]->{error};
  +    $err ? $err : "";
  +}
  +
  +sub numrows {             # OVERRIDE IN SUBCLASS
  +    my $num = $_[0]->{numrows};
  +    $num ? $num : 0;
  +}
  +
  +#  $repdate = $rep->format_repdate($date_string);   # free-form date string as 
entered by a person
  +sub format_repdate {
  +    my ($self, $datetext) = @_;
  +    my ($monthtext, $mon, $day, $year, %mon, $date);
  +    if ($datetext =~ /\b([a-zA-Z]+)[- ]+([0-9]{1,2})[- ,]+([0-9]{2,4})\b/) {  # 
i.e. December 31, 1999, 9-march-01
  +        $monthtext = $1;
  +        $day = $2;
  +        $year = $3;
  +    }
  +    elsif ($datetext =~ /\b([0-9]{1,2})[- ]+([a-zA-Z]+)[- ]+([0-9]{2,4})\b/) {  # 
i.e. 31-Dec-1999, 9 march 01
  +        $day = $1;
  +        $monthtext = $2;
  +        $year = $3;
  +    }
  +    elsif ($datetext =~ /\b([0-9]{4})([0-9]{2})([0-9]{2})\b/) {     # i.e. 
19991231, 20010309
  +        $year = $1;
  +        $mon = $2;
  +        $day = $3;
  +    }
  +    elsif ($datetext =~ m!\b([0-9]{4})[- /]+([0-9]{1,2})[- /]+([0-9]{1,2})\b!) { # 
i.e. 1999-12-31, 2001/3/09
  +        $year = $1;
  +        $mon = $2;
  +        $day = $3;
  +    }
  +    elsif ($datetext =~ m!\b([0-9]{1,2})[- /]+([0-9]{1,2})[- /]+([0-9]{2,4})\b!) {  
# i.e. 12/31/1999, 3-9-01
  +        $mon = $1;
  +        $day = $2;
  +        $year = $3;
  +    }
  +    else {
  +        return("");
  +    }
  +    if ($monthtext) {
  +        if    ($monthtext =~ /^jan/i) { $mon =  1; }
  +        elsif ($monthtext =~ /^feb/i) { $mon =  2; }
  +        elsif ($monthtext =~ /^mar/i) { $mon =  3; }
  +        elsif ($monthtext =~ /^apr/i) { $mon =  4; }
  +        elsif ($monthtext =~ /^may/i) { $mon =  5; }
  +        elsif ($monthtext =~ /^jun/i) { $mon =  6; }
  +        elsif ($monthtext =~ /^jul/i) { $mon =  7; }
  +        elsif ($monthtext =~ /^aug/i) { $mon =  8; }
  +        elsif ($monthtext =~ /^sep/i) { $mon =  9; }
  +        elsif ($monthtext =~ /^oct/i) { $mon = 10; }
  +        elsif ($monthtext =~ /^nov/i) { $mon = 11; }
  +        elsif ($monthtext =~ /^dec/i) { $mon = 12; }
  +        else                          { return("");  }
  +    }
  +    if ($year < 0) { return(""); }
  +    elsif ($year < 50) { $year += 2000; }
  +    elsif ($year < 100) { $year += 1900; }
  +    elsif ($year < 1000) { return(""); }
  +    return("") if ($mon > 12);
  +    return("") if ($day > 31);
  +    sprintf("%04d-%02d-%02d",$year,$mon,$day);
  +}
  +
  +# $row = $rep->select_row ($table, \@cols, \@params, \%paramvalues);
  +sub select_row { undef; }   # OVERRIDE IN SUBCLASS
  +
  +# $rows = $rep->select_rows($table, \@cols, \@params, \%paramvalues, \@ordercols, 
$startrow, $endrow);
  +sub select_rows { undef; }  # OVERRIDE IN SUBCLASS
  +
  +# $ok = $rep->insert_row ($table, \@cols, \@colvalues);
  +sub insert_row { 0; }       # OVERRIDE IN SUBCLASS
  +
  +# $ok = $rep->insert_rows ($table, \@cols, \@rows);
  +sub insert_rows { 0; }      # OVERRIDE IN SUBCLASS
  +
  +# $ok = $rep->update_row ($table, \@cols, \@colvalues, \@keycolidx);
  +sub update_row { 0; }       # OVERRIDE IN SUBCLASS
  +
  +# $ok = $rep->update_rows($table, \@cols, \@colvalues, \@params, \%paramvalues);
  +sub update_rows { 0; }      # OVERRIDE IN SUBCLASS
  +
  +# $ok = $rep->store_row  ($table, \@cols, \@colvalues, \@keycolidx, $update_first);
  +sub store_row { 0; }        # OVERRIDE IN SUBCLASS
  +
  +# $ok = $rep->store_rows ($table, \@cols, \@rows, \@keycolidx, $update_first);
  +sub store_rows { 0; }       # OVERRIDE IN SUBCLASS
  +
  +# $ok = $rep->delete_row ($table, \@cols, \@colvalues, \@keycolidx);
  +sub delete_row { 0; }       # OVERRIDE IN SUBCLASS
  +
  +# $ok = $rep->delete_rows($table, \@params, \%paramvalues);
  +sub delete_rows { 0; }      # OVERRIDE IN SUBCLASS
  +
  +#################################################################
  +# LOADING METADATA
  +#################################################################
  +
  +# load metadata about TYPES supported by the repository
  +# and the list of TABLES in it.
  +sub load_rep_metadata {
  +    my ($self) = @_;
  +
  +    my ($repconfig, $table, $tables, $table_defs, $table_def, $native_table, $idx);
  +    $repconfig = $self->{repconfig};
  +
  +    # start with the list of tables that was configured (or the empty list)
  +    $tables = $repconfig->{tables};
  +    $tables = [] if (!defined $tables);
  +    $self->{tables} = $tables;
  +
  +    # start with the hash of tables defined (or the empty hash)
  +    $table_defs = $repconfig->{table};
  +    $table_defs = {} if (!defined $table_defs);
  +    $self->{table} = $table_defs;
  +
  +    # for each table named in the configuration, give it a number up front
  +    for ($idx = 0; $idx <= $#$tables; $idx++) {
  +        $table = $tables->[$idx];
  +        $table_defs->{$table}{idx} = $idx;
  +    }
  +
  +    # for each table in the hash (random order), add them to the end
  +    foreach $table (keys %$table_defs) {
  +        $table_def = $table_defs->{$table};
  +        $table_def->{name} = $table;
  +        $table_def->{label} = $table if (! $table_def->{label});
  + 
  +        # table has not been added to the list and it's not explicitly "hidden", so 
add it
  +        if (!defined $table_def->{idx} && ! $table_def->{hide}) {
  +            push(@$tables, $table);
  +            $table_def->{idx} = $#$tables;
  +
  +            # we're not hiding physical tables and a native table was defined, so 
make an entry
  +            if (! $self->{hide_physical}) {
  +                $native_table = $table_def->{native_table};
  +                if (defined $native_table) {
  +                    $table_defs->{$native_table} = $table_defs->{$table};
  +                }
  +            }
  +        }
  +
  +        $self->{table_labels}{$table} = $table_def->{label};
  +    }
  +
  +    my ($type, $types, $type_defs);
  +
  +    # start with the hash of types defined (or the empty hash)
  +    $type_defs = $repconfig->{type};
  +    $type_defs = {} if (!defined $type_defs);
  +    $self->{type} = $type_defs;
  +
  +    # define the standard list of Repository types
  +    $types = [ "string", "text", "integer", "float", "date", "time", "datetime", 
"binary" ];
  +    $self->{types} = $types;
  +
  +    # define the standard list of Repository labels
  +    $self->{type_labels} = {
  +        "string"   => "Characters",
  +        "text"     => "Paragraph",
  +        "integer"  => "Integer",
  +        "float"    => "Number",
  +        "date"     => "Date",
  +        "time"     => "Time",
  +        "datetime" => "Date and Time",
  +        "binary"   => "Binary Data",
  +    };
  +
  +    # figure the index in the array of each type
  +    for ($idx = 0; $idx <= $#$types; $idx++) {
  +        $type = $types->[$idx];
  +        $self->{type}{$type}{idx} = $idx;
  +    }
  +
  +    # load up all additional information from the native metadata
  +    $self->load_rep_metadata_auto();
  +}
  +
  +# load detailed metadata about a particular table, including
  +# the details about each column
  +sub load_table_metadata {
  +    my ($self, $table) = @_;
  +
  +    # if it's already been loaded, don't do it again
  +    return if (defined $self->{table}{$table}{loaded});
  +    $self->{table}{$table}{loaded} = 1;   # mark it as having been loaded
  +
  +    my ($table_def, $columns, $column, $column_def, $idx, $native_column);
  +
  +    $table_def = $self->{table}{$table};
  +    return if (!defined $table_def);
  +
  +    $columns = $table_def->{columns};
  +    if (! defined $columns) {
  +        $columns = [];
  +        $table_def->{columns} = $columns;
  +    }
  +
  +    # for each column named in the configuration, give it a number up front
  +    for ($idx = 0; $idx <= $#$columns; $idx++) {
  +        $column = $columns->[$idx];
  +        $table_def->{column}{$column}{idx} = $idx;
  +    }
  +
  +    # load up all additional information from the native metadata
  +    $self->load_table_metadata_auto($table);
  +
  +    # for each column in the hash (random order), add them to the end
  +    foreach $column (keys %{$table_def->{column}}) {
  +        $column_def = $table_def->{column}{$column};
  +        $column_def->{name} = $column;
  +        $column_def->{label} = $column if (! $column_def->{label});
  + 
  +        # column has not been added to the list and it's not explicitly "hidden", 
so add it
  +        if (!defined $column_def->{idx} && ! $column_def->{hide}) {
  +            push(@$columns, $column);
  +            $idx = $#$columns;
  +            $column_def->{idx} = $idx;
  +            $column_def->{alias}  = "c$idx" if (!defined $column_def->{alias});
  +
  +            # we're not hiding physical columns and a native table was defined, so 
make an entry
  +            if (! $self->{hide_physical}) {
  +                $native_column = $column_def->{native_column};
  +                if (defined $native_column &&
  +                    $native_column ne $column &&
  +                    !defined $table_def->{column}{$native_column}) {
  +                    $table_def->{column}{$native_column} = 
$table_def->{column}{$column};
  +                }
  +            }
  +        }
  +
  +        $table_def->{column_labels}{$column} = $column_def->{label};
  +    }
  +
  +    # if a primary key is not defined, assume it is the first column
  +    if (!defined $table_def->{prikey}) {
  +        $table_def->{prikey} = [ $table_def->{columns}[0] ];
  +    }
  +
  +    # predefine that certain required columns will be in the result set
  +    $self->set_required_columns_fetched($table);
  +    $self->clear_cache();
  +}
  +
  +sub load_rep_metadata_auto {     # OVERRIDE IN SUBCLASS (IF DESIRED)
  +    my ($self) = @_;
  +}
  +
  +sub load_table_metadata_auto {   # OVERRIDE IN SUBCLASS (IF DESIRED)
  +    my ($self, $table) = @_;
  +}
  +
  +#################################################################
  +# ACCESSING METADATA
  +#################################################################
  +
  +#  $typenames = $rep->get_type_names();     # print "@$typenames\n";
  +sub get_type_names {
  +    my ($self) = @_;
  +    $self->{types};
  +}
  +
  +#  $typelabels = $rep->get_type_labels();   # print "%$typelabels\n";
  +sub get_type_labels {
  +    my ($self) = @_;
  +    $self->{type_labels};
  +}
  +
  +#  $type = $rep->get_type($typename);       # print "%$type\n";
  +sub get_type_def {
  +    my ($self, $type) = @_;
  +    $self->{type}{$type};
  +}
  +
  +#  $tablenames  = $rep->get_table_names();  # print "@$tablenames\n";
  +sub get_table_names {
  +    my ($self) = @_;
  +    $self->{tables};
  +}
  +
  +#  $tablelabels  = $rep->get_table_labels();  # print "%$tablelabels\n";
  +sub get_table_labels {
  +    my ($self) = @_;
  +    $self->{table_labels};
  +}
  +
  +#  $table = $rep->get_table($tablename);    # print "%$table\n";
  +sub get_table_def {
  +    my ($self, $table) = @_;
  +    $self->load_table_metadata($table) if (! defined 
$self->{table}{$table}{loaded});
  +    $self->{table}{$table};
  +}
  +
  +#  $columnnames = $rep->get_column_names($tablename);  # print "@columnnames\n";
  +sub get_column_names {
  +    my ($self, $table) = @_;
  +    $self->load_table_metadata($table) if (! defined 
$self->{table}{$table}{loaded});
  +    $self->{table}{$table}{columns};
  +}
  +
  +#  $columnlabels = $rep->get_column_labels($tablename);  # print "%$columnlabels\n";
  +sub get_column_labels {
  +    my ($self, $table) = @_;
  +    $self->load_table_metadata($table) if (! defined 
$self->{table}{$table}{loaded});
  +    $self->{table}{$table}{column_labels};
  +}
  +
  +#  $column = $rep->get_column($tablename,$columnname); # print "%$column\n";
  +sub get_column_def {
  +    my ($self, $table, $column) = @_;
  +    $self->load_table_metadata($table) if (! defined 
$self->{table}{$table}{loaded});
  +    $self->{table}{$table}{column}{$column};
  +}
  +
  +#################################################################
  +# HIGH-LEVEL (CACHED) REPOSITORY OPERATIONS
  +#################################################################
  +
  +# $rep->load_cache();
  +sub load_cache {
  +    my $self = shift;
  +}
  +
  +# $rep->clear_cache();
  +sub clear_cache {
  +    my ($self, $table) = @_;
  +    my (@tables, $rows);
  +    @tables = (defined $table) ? ($table) : @{$self->{tables}};
  +    
  +    foreach $table (@tables) {
  +        $rows = $self->{table}{$table}{cache}{rows};
  +        if (!defined $rows || ref($rows) ne "ARRAY" || $#$rows > -1) {
  +            $self->{table}{$table}{cache}{rows}   = [];
  +            $self->{table}{$table}{cache}{rowidx} = {};
  +        }
  +    }
  +}
  +
  +# $rep->add_columns_fetched   ($table, \@cols);
  +# $rep->add_columns_fetched   ($table, \@cols, \@colidx);
  +sub add_columns_fetched {
  +    my ($self, $table, $colsref, $colidxref) = @_;
  +    my ($colidx, $column, $colnum, $columns_added, $cachecolumns);
  +
  +    $colidx = $self->{table}{$table}{cache}{columnidx};
  +    $cachecolumns = $self->{table}{$table}{cache}{columns};
  +
  +    $columns_added = 0;
  +    for ($colnum = 0; $colnum <= $#$colsref; $colnum++) {
  +        $column = $colsref->[$colnum];
  +        if (!defined $colidx->{$column}) {
  +            push(@$cachecolumns, $column);
  +            $colidx->{$column} = $#$cachecolumns;
  +            $columns_added = 1;
  +        }
  +        $colidxref->[$colnum] = $colidx->{$column} if (ref($colidxref) eq "ARRAY");
  +    }
  +    if ($columns_added) {  # clear the cache
  +        $self->clear_cache($table);
  +    }
  +}
  +
  +# $rep->set_required_columns_fetched($table);
  +sub set_required_columns_fetched {
  +    my ($self, $table) = @_;
  +    my ($prikeycolumns, @prikeyidx);
  +    $prikeycolumns = $self->{table}{$table}{prikey};
  +    $self->add_columns_fetched($table, $prikeycolumns, \@prikeyidx);
  +    $self->{table}{$table}{prikeyidx} = \@prikeyidx;
  +}
  +
  +# $rep->clear_columns_fetched ($table);
  +sub clear_columns_fetched {
  +    my ($self, $table) = @_;
  +    $self->{table}{$table}{cache}{columnidx} = {};
  +    $self->{table}{$table}{cache}{columns} = [];
  +    $self->set_required_columns_fetched($table);
  +}
  +
  +# $rep->set_row_hint ($table, \%paramvalues);
  +sub set_row_hint {
  +    my ($self, $table, $paramvalueshashref) = @_;
  +    $self->{table}{$table}{cache}{paramvalues} = { %$paramvalueshashref };
  +}
  +
  +# $rep->clear_row_hint    ($table);
  +sub clear_row_hint {
  +    my ($self, $table) = @_;
  +    $self->{table}{$table}{cache}{paramvalues} = {};
  +}
  +
  +# $rows = $rep->get_rows($table, undef, \%paramvalues);
  +# $rows = $rep->get_rows($table, \@cols, \%paramvalues);
  +# $rows = $rep->get_rows($table, \@cols, \%paramvalues, \@keys);
  +sub get_rows {
  +    my ($self, $table, $colsref, $paramvalueshashref, $keysref) = @_;
  +    my ($rows, $row, $keycolidxref, $cacherows, $cacherowidx, $cachecolumns, $key);
  +
  +    $self->add_columns_fetched($table, $colsref) if (defined $colsref);
  +
  +    $cachecolumns = $self->{table}{$table}{cache}{columns};
  +    $rows = $self->select_rows($table, $cachecolumns, undef, $paramvalueshashref);
  +
  +    $keycolidxref = $self->{table}{$table}{prikey};
  +    $cacherows    = $self->{table}{$table}{cache}{rows};
  +    $cacherowidx  = $self->{table}{$table}{cache}{rowidx};
  +
  +    foreach $row (@$rows) {
  +        $key = join(",", @{$row}[@$keycolidxref]);
  +        if (!defined $cacherowidx->{$key}) {
  +            push(@$cacherows, $row);
  +            $cacherowidx->{$key} = $#$cacherows;
  +        }
  +        push (@$keysref, $key) if (ref($keysref) eq "ARRAY");
  +    }
  +
  +    $rows;
  +}
  +
  +# $row = $rep->get_row ($table, $key);
  +sub get_row {
  +    my ($self, $table, $key) = @_;
  +    my ($row, $keycolidxref, $cacherows, $cacherowidx, $cacheparamvalues, $rowidx, 
$cachecolumns);
  +
  +    $cacherows    = $self->{table}{$table}{cache}{rows};
  +    $cacherowidx  = $self->{table}{$table}{cache}{rowidx};
  +
  +    # if cache is empty, preload it with rows as hinted
  +    if ($#$cacherows == -1) {
  +        $cacheparamvalues = $self->{table}{$table}{cache}{paramvalues};
  +        $self->get_rows($table, undef, $cacheparamvalues);
  +    }
  +
  +    $rowidx = $cacherowidx->{$key};   # look in cache
  +    if (defined $rowidx) {            # if found...
  +        $row = $cacherows->[$rowidx]; #    we have our row!
  +    }
  +    else {
  +        my (%paramvalues, $i, @key, $keycolidx);
  +
  +        $keycolidxref = $self->{table}{$table}{prikey};
  +        $cachecolumns = $self->{table}{$table}{cache}{columns};
  +
  +        @key = split(/,/,$key);
  +        for ($i = 0; $i <= $#key; $i++) {
  +            $keycolidx = $keycolidxref->[$i];
  +            $paramvalues{$cachecolumns->[$keycolidx]} = $key[$i];
  +        }
  +
  +        $row = $self->select_row($table, $cachecolumns, undef, \%paramvalues);
  +
  +        $key = join(",", @{$row}[@$keycolidxref]);
  +        push(@$cacherows, $row);
  +        $cacherowidx->{$key} = $#$cacherows;
  +    }
  +
  +    $row;
  +}
  +
  +# @keys = $rep->get_keys($table, \%paramvalues);
  +sub get_keys {
  +    my ($self, $table, $paramvalueshashref) = @_;
  +    my (@keys);
  +    $self->get_rows($table, undef, $paramvalueshashref, \@keys);
  +    if (wantarray) {
  +        return (@keys)
  +    }
  +    else {
  +        return ($#keys > -1) ? $keys[0] : undef;
  +    }
  +}
  +
  +# @keys = $rep->get_related_keys($table, $key, $related_table, $relation);
  +# TODO:
  +sub get_related_keys {
  +    my ($self, $table, $key, $related_table, $relation) = @_;
  +    my (@keys);
  +}
  +
  +# @values = $rep->get_values($table, $key, \@cols);
  +sub get_values {
  +    my ($self, $table, $key, $colsref) = @_;
  +    my (@colidx, $row);
  +    $self->add_columns_fetched($table, $colsref, \@colidx);
  +    $row = $self->get_row($table, $key);
  +    @{$row}[@colidx];
  +}
  +
  +# $value  = $rep->get_value ($table, $key, $col);
  +sub get_value {
  +    my ($self, $table, $key, $column) = @_;
  +    my ($value, $row, $colidx);
  +    $colidx = $self->{table}{$table}{cache}{columnidx}{$column};
  +    if (!defined $colidx) {
  +        $self->add_columns_fetched($table, [ $column ]);
  +        $colidx = $self->{table}{$table}{cache}{columnidx}{$column};
  +    }
  +    $row = $self->get_row($table, $key);
  +    $row->[$colidx];
  +}
  +
  +# $key = $rep->set_values($table, $key, \@cols, \@values);
  +sub set_values {
  +    my ($self, $table, $key, $colsref, $valuesref) = @_;
  +    my (@colidx, $row, $i, $cacherowidx);
  +    $self->add_columns_fetched($table, $colsref, \@colidx);
  +    $cacherowidx = $self->{table}{$table}{cache}{rowidx}{$key};
  +    if (defined $cacherowidx) {
  +        $row = $self->{table}{$table}{cache}{rows}[$cacherowidx];
  +    }
  +    else {
  +        $row = $self->get_row($table, $key);
  +        $cacherowidx = $self->{table}{$table}{cache}{rowidx}{$key};
  +    }
  +    for ($i = 0; $i <= $#$colsref; $i++) {
  +        $row->[$colidx[$i]] = $valuesref->[$i];
  +    }
  +    $self->{table}{$table}{cache}{rowchange}[$cacherowidx] = "U";
  +}
  +
  +# $key = $rep->set_value ($table, $key, "first_name", $value);
  +sub set_value {
  +    my ($self, $table, $key, $column, $value) = @_;
  +    my ($row, $colidx, $cacherowidx);
  +    $colidx = $self->{table}{$table}{cache}{columnidx}{$column};
  +    if (!defined $colidx) {
  +        $self->add_columns_fetched($table, [ $column ]);
  +        $colidx = $self->{table}{$table}{cache}{columnidx}{$column};
  +    }
  +    $cacherowidx = $self->{table}{$table}{cache}{rowidx}{$key};
  +    if (defined $cacherowidx) {
  +        $row = $self->{table}{$table}{cache}{rows}[$cacherowidx];
  +    }
  +    else {
  +        $row = $self->get_row($table, $key);
  +        $cacherowidx = $self->{table}{$table}{cache}{rowidx}{$key};
  +    }
  +    $row->[$colidx] = $value;
  +    $self->{table}{$table}{cache}{rowchange}[$cacherowidx] = "U";
  +    $key;
  +}
  +
  +# @idx  = $rep->get_column_idx($table, \@cols);
  +sub get_column_idx {
  +    my ($self, $table, $colsref) = @_;
  +    my (@idx);
  +}
  +
  +# @columns = $rep->get_required_columns($table);
  +sub get_required_columns {
  +    my ($self, $table) = @_;
  +    my (@columns);
  +}
  +
  +# $rep->commit();
  +sub commit {
  +    my $self = shift;
  +    my ($table, $rows, $rowidx, $rowchange, $change, $colref, $prikeyidx);
  +    foreach $table (@{$self->{tables}}) {
  +        $prikeyidx = $self->{table}{$table}{prikeyidx};
  +        $rows      = $self->{table}{$table}{cache}{rows};
  +        $rowchange = $self->{table}{$table}{cache}{rowchange};
  +        $colref    = $self->{table}{$table}{cache}{columns};
  +        if ($#$rowchange > -1) {
  +            for ($rowidx = 0; $rowidx <= $#$rows; $rowidx++) {
  +                $change = $rowchange->[$rowidx];
  +                next if (!defined $change);
  +                if ($change eq "U") {
  +                    $self->update_row($table, $colref, $rows->[$rowidx], 
$prikeyidx);
  +                    $rowchange->[$rowidx] = "";
  +                }
  +                elsif ($change eq "I") {
  +                    $self->insert_row($table, $colref, $rows->[$rowidx]);
  +                    $rowchange->[$rowidx] = "";
  +                }
  +            }
  +        }
  +    }
  +}
  +
  +# $rep->rollback();
  +sub rollback {
  +    my $self = shift;
   }
   
   =head1 ACKNOWLEDGEMENTS
  
  
  
  1.3       +2 -1      p5ee/P5EEx/Blue/P5EEx/Blue/Security.pm
  
  Index: Security.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Security.pm,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- Security.pm       2001/11/30 16:00:52     1.2
  +++ Security.pm       2001/12/05 22:45:03     1.3
  @@ -1,10 +1,11 @@
   
   #############################################################################
  -## $Id: Security.pm,v 1.2 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Security.pm,v 1.3 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Security;
   
  +use P5EEx::Blue::P5EE;
   use P5EEx::Blue::Service;
   @ISA = ( "P5EEx::Blue::Service" );
   
  
  
  
  1.3       +45 -10    p5ee/P5EEx/Blue/P5EEx/Blue/Serializer.pm
  
  Index: Serializer.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Serializer.pm,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- Serializer.pm     2001/11/30 16:00:52     1.2
  +++ Serializer.pm     2001/12/05 22:45:03     1.3
  @@ -1,13 +1,20 @@
   
   #############################################################################
  -## $Id: Serializer.pm,v 1.2 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Serializer.pm,v 1.3 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Serializer;
   
  +use P5EEx::Blue::P5EE;
   use P5EEx::Blue::Service;
   @ISA = ( "P5EEx::Blue::Service" );
   
  +use Data::Dumper;
  +# use Compress::Zlib;
  +# use MIME::Base64;
  +# use Digest::HMAC_MD5;
  +# use Crypt::CBC;
  +
   use strict;
   
   =head1 NAME
  @@ -59,9 +66,11 @@
   
   =item * Class: P5EEx::Blue::Serializer::Storable
   
  +=item * Class: P5EEx::Blue::Serializer::XMLSimple
  +
   =item * Class: P5EEx::Blue::Serializer::XML
   
  -=item * Class: P5EEx::Blue::Serializer::IniFile
  +=item * Class: P5EEx::Blue::Serializer::Ini
   
   =item * Class: P5EEx::Blue::Serializer::Properties
   
  @@ -159,6 +168,7 @@
   =head2 deserialize()
   
       * Signature: $serialized_data = $serializer->deserialize($data);
  +    * Signature: $serialized_data = P5EEx::Blue::Serializer->deserialize($data);
       * Param:     $data              ref
       * Return:    $serialized_data   binary
       * Throws:    P5EEx::Blue::Exception::Serializer
  @@ -176,8 +186,33 @@
   
   sub deserialize {
       my ($self, $serialized_data) = @_;
  -    my ($data);
  +    my ($data, $serializer_class);
       $data = {};
  +    $serializer_class = "";
  +
  +    if ($self eq "P5EEx::Blue::Serializer") {  # static method call
  +
  +        if ($serialized_data =~ s/#Serializer +([^ ]+) +\((.*)\)\n//) {
  +            $serializer_class = $1;
  +        }
  +        elsif ($serialized_data =~ /^<!DOCTYPE/i) {
  +            $serializer_class = "P5EEx::Blue::Serializer::XML";
  +        }
  +        elsif ($serialized_data =~ /^</) {
  +            $serializer_class = "P5EEx::Blue::Serializer::XMLSimple";
  +        }
  +    }
  +
  +    if ($serializer_class) {
  +        eval "use $serializer_class;";
  +        if ($@) {
  +            P5EEx::Blue::Exception::Serializer->throw(
  +                error => "create(): error loading $serializer_class serializer 
class\n"
  +            );
  +        }
  +        $data = $serializer_class->deserialize($serialized_data);
  +    }
  +    else {
       if ($serialized_data =~ /^\$[a-zA-Z][a-zA-Z0-9_]* *= *(\{.*\};[ \n]*)$/s) {
           $serialized_data = "\$data = $1";   # untainted now
           eval($serialized_data);
  @@ -186,6 +221,8 @@
       else {
           die "Deserialization Error: Data didn't have \"\$var = {...};\" format.";
       }
  +    }
  +
       $data;
   }
   
  @@ -210,8 +247,6 @@
       print $serializer->dump($data), "\n";
   
   =cut
  -
  -use Data::Dumper;
   
   sub dump {
       my ($self, $data) = @_;
  
  
  
  1.3       +3 -1      p5ee/P5EEx/Blue/P5EEx/Blue/Service.pm
  
  Index: Service.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Service.pm,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- Service.pm        2001/11/30 16:00:52     1.2
  +++ Service.pm        2001/12/05 22:45:03     1.3
  @@ -1,11 +1,13 @@
   
   #############################################################################
  -## $Id: Service.pm,v 1.2 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Service.pm,v 1.3 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Service;
   
   use strict;
  +
  +use P5EEx::Blue::P5EE;
   
   =head1 NAME
   
  
  
  
  1.2       +2 -1      p5ee/P5EEx/Blue/P5EEx/Blue/Session.pm
  
  Index: Session.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Session.pm,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -w -r1.1 -r1.2
  --- Session.pm        2001/11/30 16:00:52     1.1
  +++ Session.pm        2001/12/05 22:45:03     1.2
  @@ -1,10 +1,11 @@
   
   #############################################################################
  -## $Id: Session.pm,v 1.1 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Session.pm,v 1.2 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Session;
   
  +use P5EEx::Blue::P5EE;
   use P5EEx::Blue::Service;
   @ISA = ( "P5EEx::Blue::Service" );
   
  
  
  
  1.3       +2 -1      p5ee/P5EEx/Blue/P5EEx/Blue/Widget.pm
  
  Index: Widget.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Widget.pm,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- Widget.pm 2001/11/30 16:00:52     1.2
  +++ Widget.pm 2001/12/05 22:45:03     1.3
  @@ -1,10 +1,11 @@
   
   #############################################################################
  -## $Id: Widget.pm,v 1.2 2001/11/30 16:00:52 spadkins Exp $
  +## $Id: Widget.pm,v 1.3 2001/12/05 22:45:03 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Widget;
   
  +use P5EEx::Blue::P5EE;
   use P5EEx::Blue::Service;
   @ISA = ( "P5EEx::Blue::Service" );
   
  
  
  
  1.1                  p5ee/P5EEx/Blue/P5EEx/Blue/LogChannel.pm
  
  Index: LogChannel.pm
  ===================================================================
  
  #############################################################################
  ## $Id: LogChannel.pm,v 1.1 2001/12/05 22:45:03 spadkins Exp $
  #############################################################################
  
  package P5EEx::Blue::LogChannel;
  
  use P5EEx::Blue::P5EE;
  use P5EEx::Blue::Service;
  @ISA = ( "P5EEx::Blue::Service" );
  
  use strict;
  
  =head1 NAME
  
  P5EEx::Blue::LogChannel - Interface for logging
  
  =head1 SYNOPSIS
  
      use P5EEx::Blue::P5EE;
  
      $context = P5EEx::Blue::P5EE->context();
      $logchannel = $context->service("LogChannel");  # or ...
      $logchannel = $context->logchannel();
  
  =head1 DESCRIPTION
  
  A LogChannel service is a means by which messages are logged through a
  logging system.  This perhaps ends up in a file, or perhaps it
  ends up on someone's operator console screen somewhere.
  
  =cut
  
  #############################################################################
  # CLASS GROUP
  #############################################################################
  
  =head1 Class Group: LogChannel
  
  The following classes might be a part of the LogChannel Class Group.
  
  =over
  
  =item * Class: P5EEx::Blue::LogChannel
  
  =item * Class: P5EEx::Blue::LogChannel::LogDispatch
  
  =item * Class: P5EEx::Blue::LogChannel::NetDaemon
  
  =item * Class: P5EEx::Blue::LogChannel::Tivoli
  
  =back
  
  =cut
  
  #############################################################################
  # CLASS
  #############################################################################
  
  =head1 Class: P5EEx::Blue::LogChannel
  
  A LogChannel service ...
  
   * Throws: P5EEx::Blue::Exception::LogChannel
   * Since:  0.01
  
  =head2 Class Design
  
  ...
  
  =cut
  
  #############################################################################
  # CONSTRUCTOR METHODS
  #############################################################################
  
  =head1 Constructor Methods:
  
  =cut
  
  #############################################################################
  # new()
  #############################################################################
  
  =head2 new()
  
  The constructor is inherited from
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service/"new()">.
  
  =cut
  
  #############################################################################
  # PUBLIC METHODS
  #############################################################################
  
  =head1 Public Methods:
  
  =cut
  
  #############################################################################
  # log()
  #############################################################################
  
  =head2 log()
  
      * Signature: $logchannel->log(@text);
      * Param:     @text              array[string]
      * Return:    void
      * Throws:    P5EEx::Blue::Exception::LogChannel
      * Since:     0.01
  
      Sample Usage: 
  
      $context = P5EEx::Blue::P5EE->context();
      $logchannel = $context->service("LogChannel");  # or ...
      $logchannel->log("Error occurred");
  
  =cut
  
  sub log {
      my ($self, @text) = @_;
      print STDERR @text, "\n";
  }
  
  =head1 ACKNOWLEDGEMENTS
  
   * Author:  Stephen Adkins <[EMAIL PROTECTED]>
   * License: This is free software. It is licensed under the same terms as Perl 
itself.
  
  =head1 SEE ALSO
  
  L<C<P5EEx::Blue::Context>|P5EEx::Blue::Context>,
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service>
  
  =cut
  
  1;
  
  
  
  
  1.1                  p5ee/P5EEx/Blue/P5EEx/Blue/Template.pm
  
  Index: Template.pm
  ===================================================================
  
  #############################################################################
  ## $Id: Template.pm,v 1.1 2001/12/05 22:45:03 spadkins Exp $
  #############################################################################
  
  package P5EEx::Blue::Template;
  
  use P5EEx::Blue::P5EE;
  use P5EEx::Blue::Service;
  @ISA = ( "P5EEx::Blue::Service" );
  
  use strict;
  
  =head1 NAME
  
  P5EEx::Blue::Template - Interface for rendering HTML templates
  
  =head1 SYNOPSIS
  
      use P5EEx::Blue::P5EE;
  
      $context = P5EEx::Blue::P5EE->context();
      $template = $context->service("Template");  # or ...
      $template = $context->template();
  
      ... TBD ...
  
  =head1 DESCRIPTION
  
  A Template Service is a means by which a template (such as an
  HTML template) may be rendered (with variables interpolated).
  
  =cut
  
  #############################################################################
  # CLASS GROUP
  #############################################################################
  
  =head1 Class Group: Template
  
  The following classes might be a part of the Template Class Group.
  
  =over
  
  =item * Class: P5EEx::Blue::Template
  
  =item * Class: P5EEx::Blue::Template::TemplateToolkit
  
  =item * Class: P5EEx::Blue::Template::Embperl
  
  =item * Class: P5EEx::Blue::Template::Mason
  
  =item * Class: P5EEx::Blue::Template::AxKit
  
  =item * Class: P5EEx::Blue::Template::ASP
  
  =item * Class: P5EEx::Blue::Template::CGIFastTemplate
  
  =item * Class: P5EEx::Blue::Template::TextTemplate
  
  =item * Class: P5EEx::Blue::Template::HTMLTemplate
  
  =back
  
  =cut
  
  #############################################################################
  # CLASS
  #############################################################################
  
  =head1 Class: P5EEx::Blue::Template
  
  A Template Service is a means by which a template (such as an
  HTML template) may be rendered (with variables interpolated).
  
   * Throws: P5EEx::Blue::Exception::Template
   * Since:  0.01
  
  =head2 Class Design
  
  ...
  
  =cut
  
  #############################################################################
  # CONSTRUCTOR METHODS
  #############################################################################
  
  =head1 Constructor Methods:
  
  =cut
  
  #############################################################################
  # new()
  #############################################################################
  
  =head2 new()
  
  The constructor is inherited from
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service/"new()">.
  
  =cut
  
  #############################################################################
  # PUBLIC METHODS
  #############################################################################
  
  =head1 Public Methods:
  
  =cut
  
  #############################################################################
  # TBD()
  #############################################################################
  
  =head2 TBD()
  
      * Signature: $tbd_return = $repository->tbd($tbd_param);
      * Param:     $tbd_param         integer
      * Return:    $tbd_return        integer
      * Throws:    P5EEx::Blue::Exception::Repository
      * Since:     0.01
  
      Sample Usage:
  
      $tbd_return = $repository->tbd($tbd_param);
  
  =cut
  
  sub tbd {
      my ($self) = @_;
  }
  
  =head1 ACKNOWLEDGEMENTS
  
   * Author:  Stephen Adkins <[EMAIL PROTECTED]>
   * License: This is free software. It is licensed under the same terms as Perl 
itself.
  
  =head1 SEE ALSO
  
  L<C<P5EEx::Blue::Context>|P5EEx::Blue::Context>,
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service>
  
  =cut
  
  1;
  
  
  
  
  1.1                  p5ee/P5EEx/Blue/P5EEx/Blue/Config/File.pm
  
  Index: File.pm
  ===================================================================
  
  #############################################################################
  ## $Id: File.pm,v 1.1 2001/12/05 22:45:04 spadkins Exp $
  #############################################################################
  
  package P5EEx::Blue::Config::File;
  $VERSION = do { my @r=(q$Revision: 1.1 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r};
  
  use P5EEx::Blue::P5EE;
  use P5EEx::Blue::Config;
  @ISA = ( "P5EEx::Blue::Config" );
  
  use strict;
  
  sub create {
      my $self = shift;
      my $args = $self->SUPER::create(@_);
      local(*FILE);
  
      my ($file, $testfile, $dir, @files, $filetype, $serializer_class, $open);
      $file = $args->{configFile};
      $file = $ENV{P5EE_CONFIG_FILE} if (!$file);
      $serializer_class = $ENV{P5EE_CONFIG_FILE_SERIALIZER};
  
      $dir = $0;
      if ($dir =~ m!/[^/]+$!) {
          $dir =~ s!/[^/]+$!!;
      }
      else {
          $dir = ".";
      }
      $dir = "." if (!$dir);
  
      if (!$file) {  # no file specified
          foreach $filetype qw(pl xml ini properties) {
              $testfile = ($dir eq ".") ? "config.$filetype" : "$dir/config.$filetype";
              if (-r $testfile) {
                  $file = $testfile;
                  last;
              }
          }
      }
  
      if (! -r $file && $dir ne ".") {
          $testfile = "$dir/$file";
          $file = $testfile if (-r $testfile);
      }
  
      if (!$file) {
          P5EEx::Blue::Exception::Config->throw(
              error => "create(): no config file specified or found\n"
          );
      }
  
      if (! open(main::FILE,"< $file")) {
          P5EEx::Blue::Exception::Config->throw(
              error => "create(): [$file] $!\n"
          );
      }
  
      my (@text, $text, $conf);
      @text = <main::FILE>;
      close(main::FILE);
      $text = join("",@text);
  
      if (!$serializer_class) {
  
          $filetype = "";
          if ($file =~ /\.([^\.]+)$/) {
              $filetype = $1;
          }
  
          if ($filetype eq "pl") {
              $serializer_class = "P5EEx::Blue::Serializer";
          }
          elsif ($filetype eq "stor") {
              $serializer_class = "P5EEx::Blue::Serializer::Storable";
          }
          elsif ($filetype eq "xml") {
              $serializer_class = "P5EEx::Blue::Serializer::XMLSimple";
          }
          elsif ($filetype eq "ini") {
              $serializer_class = "P5EEx::Blue::Serializer::Ini";
          }
          elsif ($filetype eq "properties") {
              $serializer_class = "P5EEx::Blue::Serializer::Properties";
          }
          elsif ($filetype) {
              my $serializer = uc(substr($filetype,0,1)) . substr($filetype,1);
              $serializer_class = "P5EEx::Blue::Serializer::$serializer";
          }
          else {
              $serializer_class = "P5EEx::Blue::Serializer";
          }
      }
  
      eval "use $serializer_class;";
      if ($@) {
          P5EEx::Blue::Exception::Config->throw(
              error => "create(): error loading $serializer_class serializer class\n"
          );
      }
      $conf = $serializer_class->deserialize($text);
  
      $conf;
  }
  
  1;
  
  
  
  
  1.1                  p5ee/P5EEx/Blue/P5EEx/Blue/Serializer/Storable.pm
  
  Index: Storable.pm
  ===================================================================
  
  #############################################################################
  ## $Id: Storable.pm,v 1.1 2001/12/05 22:45:04 spadkins Exp $
  #############################################################################
  
  package P5EEx::Blue::Serializer::Storable;
  
  use P5EEx::Blue::P5EE;
  use P5EEx::Blue::Serializer;
  @ISA = ( "P5EEx::Blue::Serializer" );
  
  use strict;
  
  =head1 NAME
  
  P5EEx::Blue::Serializer::Storable - Interface for serialization and deserialization
  
  =head1 SYNOPSIS
  
      use P5EEx::Blue::P5EE;
  
      $context = P5EEx::Blue::P5EE->context();
      $serializer = $context->service("Serializer");  # or ...
      $serializer = $context->serializer();
      $data = {
          an => 'arbitrary',
          collection => [ 'of', 'data', ],
          of => {
              arbitrary => 'depth',
          },
      };
      $stor = $serializer->serialize($data);
      $data = $serializer->deserialize($stor);
      print $serializer->dump($data), "\n";
  
  =head1 DESCRIPTION
  
  A Serializer allows you to serialize a structure of data
  of arbitrary depth to a scalar and deserialize it back to the
  structure.
  
  The Storable serializer uses
  the Storable class to perform
  the deserialization and serialization.
  
  =cut
  
  #############################################################################
  # CLASS
  #############################################################################
  
  =head1 Class: P5EEx::Blue::Serializer::Storable
  
   * Throws: P5EEx::Blue::Exception::Serializer
   * Since:  0.01
  
  =head2 Design
  
  The class is entirely made up of static (class) methods.
  However, they are each intended to be
  called as methods on the instance itself.
  
  =cut
  
  #############################################################################
  # CONSTRUCTOR METHODS
  #############################################################################
  
  =head1 Constructor Methods:
  
  =cut
  
  #############################################################################
  # new()
  #############################################################################
  
  =head2 new()
  
  The constructor is inherited from
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service/"new()">.
  
  =cut
  
  #############################################################################
  # PUBLIC METHODS
  #############################################################################
  
  =head1 Public Methods:
  
  =cut
  
  #############################################################################
  # serialize()
  #############################################################################
  
  =head2 serialize()
  
      * Signature: $stor = $serializer->serialize($data);
      * Param:     $data              ref
      * Return:    $stor              binary
      * Throws:    P5EEx::Blue::Exception::Serializer
      * Since:     0.01
  
      Sample Usage: 
  
      $context = P5EEx::Blue::P5EE->context();
      $serializer = $context->service("Serializer");  # or ...
      $serializer = $context->serializer();
      $data = {
          an => 'arbitrary',
          collection => [ 'of', 'data', ],
          of => {
              arbitrary => 'depth',
          },
      };
      $stor = $serializer->serialize($data);
  
  =cut
  
  use Storable qw(freeze thaw);
  
  sub serialize {
      my ($self, $data) = @_;
      my ($stor);
  
      $stor = freeze($data);
  
      return $stor;
  }
  
  #############################################################################
  # deserialize()
  #############################################################################
  
  =head2 deserialize()
  
      * Signature: $data = $serializer->deserialize($stor);
      * Signature: $data = P5EEx::Blue::Serializer->deserialize($stor);
      * Param:     $data              ref
      * Return:    $stor              binary
      * Throws:    P5EEx::Blue::Exception::Serializer
      * Since:     0.01
  
      Sample Usage: 
  
      $context = P5EEx::Blue::P5EE->context();
      $serializer = $context->service("Serializer");  # or ...
      $serializer = $context->serializer();
      $data = $serializer->deserialize($stor);
      print $serializer->dump($data), "\n";
  
  =cut
  
  sub deserialize {
      my ($self, $stor) = @_;
      my ($data);
  
      $data = thaw($stor);
  
      return $data;
  }
  
  #############################################################################
  # dump()
  #############################################################################
  
  =head2 dump()
  
  This method is inherited from
  L<C<P5EEx::Blue::Serializer>|P5EEx::Blue::Serializer/"dump()">.
  
  =head1 ACKNOWLEDGEMENTS
  
   * Author:  Stephen Adkins <[EMAIL PROTECTED]>
   * License: This is free software. It is licensed under the same terms as Perl 
itself.
  
  =head1 SEE ALSO
  
  L<C<P5EEx::Blue::Context>|P5EEx::Blue::Context>,
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service>
  
  =cut
  
  1;
  
  
  
  
  1.1                  p5ee/P5EEx/Blue/P5EEx/Blue/Serializer/XMLSimple.pm
  
  Index: XMLSimple.pm
  ===================================================================
  
  #############################################################################
  ## $Id: XMLSimple.pm,v 1.1 2001/12/05 22:45:04 spadkins Exp $
  #############################################################################
  
  package P5EEx::Blue::Serializer::XMLSimple;
  
  use P5EEx::Blue::P5EE;
  use P5EEx::Blue::Serializer;
  @ISA = ( "P5EEx::Blue::Serializer" );
  
  use strict;
  
  =head1 NAME
  
  P5EEx::Blue::Serializer::XMLSimple - Interface for serialization and deserialization
  
  =head1 SYNOPSIS
  
      use P5EEx::Blue::P5EE;
  
      $context = P5EEx::Blue::P5EE->context();
      $serializer = $context->service("Serializer");  # or ...
      $serializer = $context->serializer();
      $data = {
          an => 'arbitrary',
          collection => [ 'of', 'data', ],
          of => {
              arbitrary => 'depth',
          },
      };
      $xml = $serializer->serialize($data);
      $data = $serializer->deserialize($xml);
      print $serializer->dump($data), "\n";
  
  =head1 DESCRIPTION
  
  A Serializer allows you to serialize a structure of data
  of arbitrary depth to a scalar and deserialize it back to the
  structure.
  
  The XMLSimple serializer uses non-validated XML as the serialized
  form of the data.  It uses the XML::Simple class to perform
  the deserialization and serialization.
  
  =cut
  
  #############################################################################
  # CLASS
  #############################################################################
  
  =head1 Class: P5EEx::Blue::Serializer::XMLSimple
  
   * Throws: P5EEx::Blue::Exception::Serializer
   * Since:  0.01
  
  =head2 Design
  
  The class is entirely made up of static (class) methods.
  However, they are each intended to be
  called as methods on the instance itself.
  
  =cut
  
  #############################################################################
  # CONSTRUCTOR METHODS
  #############################################################################
  
  =head1 Constructor Methods:
  
  =cut
  
  #############################################################################
  # new()
  #############################################################################
  
  =head2 new()
  
  The constructor is inherited from
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service/"new()">.
  
  =cut
  
  #############################################################################
  # PUBLIC METHODS
  #############################################################################
  
  =head1 Public Methods:
  
  =cut
  
  #############################################################################
  # serialize()
  #############################################################################
  
  =head2 serialize()
  
      * Signature: $xml = $serializer->serialize($data);
      * Param:     $data              ref
      * Return:    $xml               text
      * Throws:    P5EEx::Blue::Exception::Serializer
      * Since:     0.01
  
      Sample Usage: 
  
      $context = P5EEx::Blue::P5EE->context();
      $serializer = $context->service("Serializer");  # or ...
      $serializer = $context->serializer();
      $data = {
          an => 'arbitrary',
          collection => [ 'of', 'data', ],
          of => {
              arbitrary => 'depth',
          },
      };
      $xml = $serializer->serialize($data);
  
  =cut
  
  use XML::Simple;
  
  sub serialize {
      my ($self, $data) = @_;
      my ($xml, $xp);
  
      $xp = XML::Simple->new(
           'keyattr' => [ 'name', ],  # turn off 'id' and 'key'
      );
  
      $xml = $xp->XMLout($data);
  
      return $xml;
  }
  
  #############################################################################
  # deserialize()
  #############################################################################
  
  =head2 deserialize()
  
      * Signature: $data = $serializer->deserialize($xml);
      * Signature: $data = P5EEx::Blue::Serializer->deserialize($xml);
      * Param:     $data              ref
      * Return:    $xml               text
      * Throws:    P5EEx::Blue::Exception::Serializer
      * Since:     0.01
  
      Sample Usage: 
  
      $context = P5EEx::Blue::P5EE->context();
      $serializer = $context->service("Serializer");  # or ...
      $serializer = $context->serializer();
      $data = $serializer->deserialize($xml);
      print $serializer->dump($data), "\n";
  
  =cut
  
  sub deserialize {
      my ($self, $xml) = @_;
      my ($data, $xp);
  
      $xp = XML::Simple->new(
           'keyattr' => [ 'name', ],  # turn off 'id' and 'key'
      );
  
      $data = $xp->XMLin($xml);
  
      return $data;
  }
  
  #############################################################################
  # dump()
  #############################################################################
  
  =head2 dump()
  
  This method is inherited from
  L<C<P5EEx::Blue::Serializer>|P5EEx::Blue::Serializer/"dump()">.
  
  =head1 ACKNOWLEDGEMENTS
  
   * Author:  Stephen Adkins <[EMAIL PROTECTED]>
   * License: This is free software. It is licensed under the same terms as Perl 
itself.
  
  =head1 SEE ALSO
  
  L<C<P5EEx::Blue::Context>|P5EEx::Blue::Context>,
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service>
  
  =cut
  
  1;
  
  
  
  
  1.2       +6 -8      p5ee/P5EEx/Blue/examples/Config.1
  
  Index: Config.1
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/examples/Config.1,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -w -r1.1 -r1.2
  --- Config.1  2001/11/17 04:56:10     1.1
  +++ Config.1  2001/12/05 22:45:04     1.2
  @@ -1,18 +1,16 @@
   #!/usr/local/bin/perl -wT
   
  +use lib ".";
   use lib "..";
   use P5EEx::Blue::P5EE;
   
   $config = P5EEx::Blue::P5EE->config();
   print "FROM PERL: ", $config->dump(), "\n";
   
  -$config = P5EEx::Blue::P5EE->config(
  -    configClass => "P5EEx::Blue::Config::XML",
  -);
  -print "FROM XML: ", $config->dump(), "\n";
  +use P5EEx::Blue::Config::File;
   
  -$config = P5EEx::Blue::P5EE->config(
  -    configClass => "P5EEx::Blue::Config::Inifiles",
  -);
  -print "FROM INI: ", $config->dump(), "\n";
  +foreach $file qw(config.pl config.xml config.ini config.properties) {
  +    $data = P5EEx::Blue::Config::File->new( configFile => $file );
  +    print "FROM $file: ", $data->dump($data), "\n";
  +}
   
  
  
  
  1.1                  p5ee/P5EEx/Blue/examples/Reference.1
  
  Index: Reference.1
  ===================================================================
  #!/usr/local/bin/perl -wT
  
  use lib ".";
  use lib "..";
  use P5EEx::Blue::P5EE;
  use P5EEx::Blue::Reference;
  
  $P5EEx::Blue::Context::DEBUG = 0;
  
  $ref = P5EEx::Blue::Reference->new();
  $ref->set("x.y.z.pi", 3.1416);
  print "1. pi=", $ref->get("x.y.z.pi"), "\n";
  $branch = $ref->get_branch("x.y.z");
  print "2. pi=", $branch->{pi}, "\n";
  $branch = $ref->get_branch("zeta.alpha");
  print "Nonexistent branch: ", ($branch ? $branch : "[undef]"), "\n";
  $branch = $ref->get_branch("zeta.alpha", 1);
  print "Existent branch: ", ($branch ? "defined" : "[undef]"), "\n";
  
  #print "dump:\n", $ref->dump(), "\n";   # use Data::Dumper to spit out the Perl 
representation
  
  $ref = P5EEx::Blue::Reference->new(
     hello => "world",
     quit => {
        following => [ 1, 3, 4, "nine", ],
        me => 1,
     },
  );
  #print "dump:\n", $ref->dump(), "\n";   # use Data::Dumper to spit out the Perl 
representation
  
  exit 0;
  
  try {
      print "trying...\n";
      $ref = P5EEx::Blue::Reference->new([], 1);
      print "tried.\n";
  }
  catch P5EEx::Blue::Exception with {
      my ($e) = @_;
      printf "desc=[%s] error=[%s] pid=[%s] gid=[%s] euid=[%s] egid=[%s] time=[%s] 
package=[%s] file=[%s] line=[%s]\n",
         $e->description(),
         $e->error(),
         $e->pid(),
         $e->uid(),
         $e->gid(),
         $e->euid(),
         $e->egid(),
         $e->time(),
         $e->package(),
         $e->file(),
         $e->line();
  }
  finally {
      print "done trying.\n";
  };
  
  $ref = P5EEx::Blue::Reference->new("x", 1, "y");
  
  # accessors
  #$property_value = $ref->get($property_name);
  #$ref->set($property_name, $property_value);
  
  # on-demand loading helper methods (private methods)
  #$ref->overlay($ref2);        # merge the two config structures using overlay rules
  #$ref->overlay($ref1, $ref2);  # merge $ref2 onto $ref1
  #$ref->graft($branch_name, $ref2);  # graft new config structure onto branch
  
  
  
  
  1.1                  p5ee/P5EEx/Blue/examples/config.ini
  
  Index: config.ini
  ===================================================================
  
  [Standard.Log-Dispatch]
  logdir = /var/p5ee
  
  [Authen]
  passwd = /etc/passwd
  seed = 303292
  
  [Session.default]
  sessionClass = P5EE::Blue::Session::CGI
  
  
  
  
  1.1                  p5ee/P5EEx/Blue/examples/config.properties
  
  Index: config.properties
  ===================================================================
  
  # this is a comment
  Standard.Log-Dispatch.logdir = /var/p5ee
  
  # regarding Authen ..
  Authen.passwd = /etc/passwd
  Authen.seed = 303292
  
  # stuff about Session.default
  Session.default.sessionClass = P5EE::Blue::Session::CGI
  
  
  
  
  1.1                  p5ee/P5EEx/Blue/examples/config.xml
  
  Index: config.xml
  ===================================================================
  
  <conf>
    <Standard>
      <Log-Dispatch logdir="/var/p5ee"/>
    </Standard>
    <Authen passwd="/etc/passwd" seed="303292"/>
    <Session>
      <default>
        <sessionClass>P5EE::Blue::Session::CGI</sessionClass>
      </default>
    </Session>
  </conf>
  
  
  
  
  1.3       +88 -7     p5ee/P5EEx/Blue/sbin/perldocs
  
  Index: perldocs
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/sbin/perldocs,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -w -r1.2 -r1.3
  --- perldocs  2001/11/30 16:00:53     1.2
  +++ perldocs  2001/12/05 22:45:04     1.3
  @@ -741,7 +741,8 @@
   
   sub write_class_group_tree {
       my ($this_class_group) = @_;
  -    my ($html);
  +    my ($html, $title);
  +    $title = ($this_class_group eq "allclasses") ? "All Class Groups" : 
"$this_class_group Class Group";
       $html = <<EOF;
   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 
Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd";>
   <!--NewPage-->
  @@ -806,7 +807,7 @@
   <HR>
   <CENTER>
   <H2>
  -Hierarchy For All Class Groups</H2>
  +Hierarchy For $title</H2>
   </CENTER>
   <DL>
   <DT>
  @@ -904,10 +905,12 @@
   sub class_group_tree {
       my ($class_group) = @_;
       my ($class, $class2, $html, $children, $classes, @root_classes, 
%selected_classes);
  +    %selected_classes = ();
       $html = "";
       $classes = $data{classgroup}{$class_group}{classes};
       if (defined $classes) {
  -        foreach $class (@$classes) {
  +        foreach (sort @$classes) {
  +            $class = $_;
               while ($data{class}{$class}{parent}) {
                   $selected_classes{$class} = 1;
                   $class = $data{class}{$class}{parent};
  @@ -917,7 +920,7 @@
                   $selected_classes{$class} = 1;
               }
           }
  -        foreach $class (@$classes) {
  +        foreach $class (sort @$classes) {
               $children = $data{class}{$class}{children};
               if (defined $children) {
                   foreach $class2 (@$children) {
  @@ -927,7 +930,7 @@
           }
   
           $html .= "<ul>\n";
  -        foreach $class (@root_classes) {
  +        foreach $class (sort @root_classes) {
               $html .= &class_tree($class, \%selected_classes);
           }
           $html .= "</ul>\n";
  @@ -958,13 +961,91 @@
       $children = $data{class}{$class}{children};
       if (defined $children) {
           $html .= "<ul>\n";
  -        foreach $class (@$children) {
  +        foreach $class (sort @$children) {
               if (!defined $selected_classes || !%$selected_classes || 
$selected_classes->{$class}) {
  -                $html .= &class_tree($class);
  +                $html .= &class_tree($class, $selected_classes);
               }
           }
           $html .= "</ul>\n";
       }
  +    $html;
  +}
  +
  +sub navbar {
  +    my ($level, $item) = @_;
  +    my ($distribution, $classgroup, $class);
  +    my (%level_label, $html);
  +
  +    %level_label = (
  +        allclasses => "Site",
  +        distribution => "Distribution",
  +        classgroup => "Class-Group",
  +        class => "Class",
  +    );
  +
  +    $html = <<EOF;
  +<!-- ========== START OF NAVBAR ========== -->
  +<A NAME="navbar_top"><!-- --></A>
  +<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
  +  <TR>
  +    <TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
  +      <A NAME="navbar_top_firstrow"><!-- --></A>
  +      <TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
  +        <TR ALIGN="center" VALIGN="top">
  +          <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">
  +            &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Site</B></FONT>&nbsp;
  +          </TD>
  +          <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev">
  +            &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Distribution</B></FONT>&nbsp;
  +          </TD>
  +          <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
  +            &nbsp;<FONT CLASS="NavBarFont1">Class-Group</FONT>&nbsp;
  +          </TD>
  +          <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
  +            &nbsp;<FONT CLASS="NavBarFont1">Class</FONT>&nbsp;
  +          </TD>
  +
  +          <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
  +            &nbsp;<FONT CLASS="NavBarFont1">Use</FONT>&nbsp;
  +          </TD>
  +          <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
  +            &nbsp;<A HREF="overview-tree.html"><FONT 
CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;
  +          </TD>
  +          <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
  +            &nbsp;<A HREF="deprecated-list.html"><FONT 
CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;
  +          </TD>
  +        </TR>
  +      </TABLE>
  +    </TD>
  +    <TD ALIGN="right" VALIGN="top" ROWSPAN=3>
  +      <EM><b>$distname-$version</b></EM>
  +    </TD>
  +  </TR>
  +
  +  <TR>
  +    <TD BGCOLOR="white" CLASS="NavBarCell2">
  +      <FONT SIZE="-2">&nbsp;PREV&nbsp;&nbsp;NEXT</FONT>
  +    </TD>
  +    <TD BGCOLOR="white" CLASS="NavBarCell2">
  +      <FONT SIZE="-2">
  +        <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>&nbsp;&nbsp;
  +        <A HREF="overview-summary.html" TARGET="_top"><B>NO 
FRAMES</B></A>&nbsp;&nbsp;
  +        <SCRIPT>
  +          <!--
  +          if(window==top) {
  +            document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All 
Classes</B></A>');
  +          }
  +          //-->
  +        </SCRIPT>
  +        <NOSCRIPT>
  +        <A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
  +        </NOSCRIPT>
  +      </FONT>
  +    </TD>
  +  </TR>
  +</TABLE>
  +<!-- =========== END OF NAVBAR =========== -->
  +EOF
       $html;
   }
   
  
  
  


Reply via email to