The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

SADI::Base - Hash-based abstract super-class for all SADI objects

SYNOPSIS

  use base qw( SADI::Base );

  $self->throw ("This is an error");

  $LOG->info ('This is an info message.');
  $LOG->error ('This is an error to be logged.');

DESCRIPTION

This is a hash-based implementation of a general sadi super-class. Most SADI objects should inherit from this.

CONTACT

Re-factored by Edward Kawas <edward.kawas@gmail.com> from a similar module in perl moses (MOSES::MOBY::Base) created by Martin Senger <martin.senger@gmail.com>.

ACCESSIBLE ATTRIBUTES

Most of the SADI objects are just containers of other objects (attributes, members). Therefore, in order to crete a new SADI object it is often enough to inherit from this SADI::Base and to list allowed attributes. The object lists only new, additional, attributes (those defined in its parent classes are already available).

This is done by creating a closure with a list of allowed attribute names. These names correspond with the allowed get and set methods. For example:

  {
    my %_allowed =
        (
         id         => undef,
         namespace  => undef,
         );
  }

The closure above allows to call:

    $obj->id;                    # a get method
    $obj->id ('my id');          # a set method

    $obj->namespace;             # a get method
    $obj->namespace ('my ns');   # a set method

Well, not yet. The closure also needs two methods that access these (and only these - that is why it is a closure, after all) attributes. Here they are:

  {
    my %_allowed =
        (
         id         => undef,
         namespace  => undef,
         );
    sub _accessible {
        my ($self, $attr) = @_;
        exists $_allowed{$attr} or $self->SUPER::_accessible ($attr);
    }
    sub _attr_prop {
        my ($self, $attr_name, $prop_name) = @_;
        my $attr = $_allowed {$attr_name};
        return ref ($attr) ? $attr->{$prop_name} : $attr if $attr;
        return $self->SUPER::_attr_prop ($attr_name, $prop_name);
    }
  }

More about these methods in a moment.

Each attribute has also associated some properties (that is why we need the second method in the closure, the _attr_prop). For example:

  {
    my %_allowed =
        (
         id         => undef,
         namespace  => undef,
         date  => {type => SADI::Base->DATETIME},
         numbers      => {type => SADI::Base->INTEGER, is_array => 1},
     primitive  => {type => SADI::Base->BOOLEAN},
         );
    ...
  }

The recognized property names are:

type

It defines a type of its attribute. It can be a primitive type - one of those defined as constants in SADI::Base (e.g. "SADI::Base->INTEGER") - or a name of a real object (e.g. SADI::RDF::Core).

When an attribute new value is being set it is checked against this type, and an exception is thrown if the value does not comply with the type.

Default type (used also when the whole properties are undef) is "SADI::Base->STRING".

is_array

A boolean property. If set to true it allows to set more values to this attribute. It also allows to call a method prefixed with add_ to add a new value (or values) to this attribute.

Default value is false.

Recognized values for true are: 1, yes, true, + and ano. Anything else is considered false.

readonly

A boolean property. If set to true the atribute can only be read.

post

A property containing a reference to a subroutine. This subroutine is called after a new value was set. It allows to do some post-processing. For example:

  {
    my %_allowed =
        (
         value  => {post => sub { shift->{isValueCDATA} = 0; } },
         );
    ...
  }

Now we know what attribute properties are - so we can define what these methods in closure do (even though you do not need to know - unless The Law of Leaky Abstractions starts showing).

_accessible ($attr_name)

Return 1 if the parameter $attr_name is an allowed name to be set/get in this class; otherwise, pass it to the parent class.

_attr_prop ($attr_name, $prop_name)

Return a value of a property given by name $prop_name for given attribute $attr_name; if such attribute does not exist here, pass it to the parent class.

THROWING EXCEPTIONS

One of the functionalities that SADI::Base provides is the ability to throw() exceptions with pretty stack traces.

throw

Throw an exception. An argument is an error message.

format_stack

Return a nicely formatted stack trace. The resul includes also an error message given as a scalar argument. Usually, this method is not called directly but via throw (unless enable_throw_with_stack was set to true).

    print $self->format_stack ("Something terrible happen.");

LOGGING

Logging is available through the $LOG variable create and exported as a result of using this module.

As a service writer, you can $LOG->info('some message'), $LOG->warn('some warning'), $LOG->debug('some debug statement') or $LOG->error('some error message').

The next question is where are these messages sent? SADISeS allows you to configure where to send messages in the log4perl.properties file. When you run sadi-install.pl this module, this file is automatically created for you and placed (usually) in your home directory in a folder called Perl-SADI. If no properties file exists, then the messages are usually placed in STDOUT.

OTHER SUBROUTINES

new

Create an empty hash-based object. Then call init() in order to do any initializing steps. This class provides only an empty init() but sub-classes may have it richer. Finally, fill the new object with the given arguments (name/value pairs). The filling is done via set methods - which means that only attributes allowed for this particular object can be used.

Arguments are name/value pairs. A special case is allowed: when a single element argument occurs, it is treated as a "value". For example, it is allowed to write:

    $sadiint = new SADI::Data::Integer (42);

instead of a long way (doing the same):

    $sadiint = new SADI::Data::Integer (value => 42);

init

Called after an object has been created (in new()) and before the values given in the constructor have been set. No arguments.

If your sub-class implements this method, make sure that it calls also the same method of its super class:

   sub init {
       my ($self) = shift;
       $self->SUPER::init();
       # ... here do what you wish to do
       # ...
   }

toString

Return an (almost) human-readable description of any object.

Without any parameter, it stringifies the caller object (self). Otherwise it stringifies the object given as parameter.

    print $self->toString;

    my $good_stuff = { yes => [1,2,3],
                       no  => { net => 'R', nikoliv => 'C' },
                   };
    print $self->toString ($good_stuff);

init_config

Find and read given configuration files (and perhaps some others). Import all their properties into SADICFG namespace. More about how to use configuration properties is in SADI::Config module.

But making a long story short, this is all what you need in your service implementation to use a property (excluding the fact that you need to know the property name):

    $self->init_config ('my.conf');
    open HELLO, $SADICFG::MABUHAY_RESOURCE_FILE
        or $self->throw ('Mabuhay resource file not found.');

Arguments are optional and contain the file names of the configuration files to be read, and/or hash references with the direct configuration arguments. The files are looking for at the paths defined in the @INC, and - if set - by the environment variable SADI_CFG_DIR.