Home | Wiki | OI 1.x Docs | OI 2.x Docs |
SPOPS -- or Simple Perl Object Persistence with Security -- allows you to easily define the structure of an object and to save, fetch or remove it any time thereafter. It is intended for SQL databases (using the DBI), but you can adapt it to use any storage mechanism for accomplishing these tasks. SPOPS also implements security on a per-object basis (authentication and authorization).
The goals of this module are:
Make it easy to define the parameters of an object
Make it easy to do common operations (fetch, save, remove)
Get rid of as much SQL as possible, but do not impose a cumbersome framework on the developer
Make applications easily portable from one database to another
Include flexibility to allow extensions
Allow the developer to simply issue SQL statements and work with normal datasets
SPOPS (Simple Perl Object Persistence with Security) provides a framework to make your application objects persistent (meaning, you can store them somewhere, e.g., in a relational database), and to control access to them (the usual user/group access rights stuff).
You will configure SPOPS by means of configuration files, and SPOPS will create the necessary classes and objects for your application on the fly. You can of course have your own code implement additional object behavior -- extending the default SPOPS object behavior with your methods. However, if SPOPS shall know about your classes and objects, you will have to tell it -- by configuring it.
The typical class hierarchy for an SPOPS object looks like this:
-------------------------- |SPOPS | -------------------------- ^ | -------------------------- |SPOPS::MyStorageTechnology| -------------------------- ^ | -------------------------- |SPOPS::MyApplicationClass | --------------------------
Abstract base class, provides persistency and security framework (fetch, save, remove)
Concrete base class, provides technical implementation of framework for a particular storage technology (e.g., Filesystem, RDBMS, LDAP, ... )
Example: SPOPS::DBI, SPOPS::GDBM, SPOPS::Imperia ...
User class, provides semantic implementation of framework (configuration of parent class, e.g., database connection strings, field mappings, ... )
Example: MyApplication::User, MyApplication::Document, ...
The individual objects in a package should not care how the objects are being stored, they should just know that when they call fetch() with a unique ID that the object magically appears. Similarly, all the object should know is that it calls save() on itself and can reappear at any later date with the proper invocation.
Basically, each SPOPS object is always in one of two states:
Runtime State
Persistency State
In Runtime State, the object representation is based on a hash of
attributes. The object gets notified about any changes to it through the
tie(3)
mechanism.
In Persistency State, the object exists in some persistent form, that is, it is stored in a database, or written out to a file.
You can control what happens to the object when it gets written to its
persistent form, or when it is deleted, or fetched from its storage form,
by implementing a simple API: fetch(),
save(),
remove().
------------- save, remove ----------------- |Runtime State| -------------------> |Persistency State| ------------- <------------------ ----------------- fetch
By adding this module into the hierarchy for an SPOPS object class, you implement a transparent per-object security system. This security system relies on a few things being implemented:
Security is implemented with a number of methods that are called
within the SPOPS implementation module. For instance, every time you
call fetch()
on an object, the system first determines
whether you have rights to do so. Similar callbacks are located in
save()
and remove()
. If you do not either
define the method in your SPOPS implementation or use this module, the
action will always be allowed.
We use a Unix-style permission scheme, separating the scope into: USER, GROUP and WORLD from most- to least-specific. (This is abbreviated as U/G/W.) When we check permissions, we check whether a security level is defined for the most-specific item first, then work our way up to the least specific.
Even though we use the U/G/W scheme from Unix, we are not constrained by its history. There is no strict 'ownership' assigned to an object as there is to a Unix file. Instead, an object can have assigned to it permissions from any number of users, and any number of groups.
There are three settings for any object combined with a specific scope:
NONE: The scope is barred from even seeing the object. READ: The scope can read the object but not save it. WRITE: The scope can read, write and delete the object.
(To be explicit: WRITE permission implies READ permission as well; if a scope has WRITE permission for an object, it can do anything with it, including remove it.)
With security, there are some important assumptions. These rules are laid out here.
For instance, look at an object that represents a news notice posted:
Object Class: MyApp::News Object ID: 1625
------------------------------------------------ | SCOPE | SCOPE_ID | NONE | READ | WRITE | ------------------------------------------------ | USER | 71827 | | X | | | USER | 6351 | X | | | | USER | 9182 | | | X | | GROUP | 762 | | X | | | GROUP | 938 | | | X | | WORLD | | | X | | ------------------------------------------------
From this, we can say: