Title: Rio Case DOB Metadata

Table of Contents

REVISION LOG

*

2. introduction

*

3. pre-pop processing ("Before you Pop")

*

3.1 Familiarizing yourself with pox and poxen

*

3.2 Using POX to describe a class.

*

3.2.1

*

A sample written description of a hypothetical class:

*

3.2.2 A sample pox description of a hypothetical class ("Us_company.pox"):

*

3.3 Setting Environment Variables prior to processing poxen.

*

3.4

*

Understanding how the pox utilities parse their parameters

*

3.5 Creating documentation using "poxhtml"

*

3.6 Creating Perl modules using "poxperl"

*

3.7 Creating database schema using "poxdb"

*

3.8 Using "schemadrop"

*

3.9

*

Using "schemaload"

*

3.10

Merging pox changes with an updated perl module *

3.11 Perl class code required when you add an attribute to your class

*

3.11.1 Scalar non-object

*

3.11.2 Scalar object

*

3.11.3 List of non-objects

*

3.11.4 List of objects

*

3.11.5 Hash of non-objects

*

3.11.6 Hash of objects

*

4. POP processing

* REVISION LOG

Version | Date | Who | Description of change
1.0 | 1/25/99 | K. Briggs | Created
1.0 | 1/29/99 | K. Briggs | Modified to reflect release 1.0 of POP and include suggested examples.
1.1 | 2/24/99 | T. Burzesi | Added section on Perl code required when you add attributes to a class as per email from B. Holzman. Removed 3.10 on updating using diff: a practice no longer used. Changed title to ‘Developer’ Guide from User Guide.

2. introduction

Perl Object Persistence (POP) will be implemented by the PPS team using implicit persistence and with all information regarding persistent objects stored in a Sybase database. This user guide has been created to help the EEIT developer understand and utilize POP as implemented here at Matthew Bender on the PPS team. This user guide also describes many POP utilities and includes many explicit examples on their use for further clarification.

3. pre-pop processing ("Before you Pop")

This section describes the steps a developer will follow prior to utilizing POP.

3.1 Familiarizing yourself with pox and poxen

POX* is a markup language conforming to the XML** specification which describes persistent class structure. We’ll refer a single file containing pox as "pox" and a collection of pox files as "poxen" from this point forward in the documentation.

* POX is an acronym for Persistent Object Xml. ** XML stands for eXtensible Markup Language.

3.2 Using POX to describe a class.

Create a separate pox file for each new class you are attempting to describe/define. When creating a new pox file, the file name should be the name of the class you’re defining and the file extension will always be "pox". Our naming convention is:

Employee_site.pox

where the class ("Employee_site" here) is the file name which always begins with a capital letter and may contain underscores for readability and with the aforementioned ".pox" file extension. A pox file should always contain information describing the class (such as name and abbreviated name if necessary), as well as information on attributes, methods, class-methods, method-parameters, and text format, if pertinent. The first line of a pox file should always contain a "version" tag used for project source control. A sample version tag would be:

<?version '$Revision: 1.1.1.1 $'?>

This will keep the revision number up-to-date each and every time the pox is checked into CVS (Concurrent Versions System; our source control software used on the PPS team). It is not necessary to create a "constructor" as constructors will be inherited from the persistent base class. Any text found in the pox elements will be considered comments regarding the element and will appear in the documentation created from the pox files. (The procedure on how to generate html documentation from any text found in the pox appears later in this document in the section entitled: "Create documentation using ‘poxhtml’").

In addition to the aforementioned version tag, the pox file will also contain one or more pox elements which will each help to further define the class. Each pox element, as well as the attributes for each, should be as outlined in the following table:

Element | Parents | Attributes | Description
class | <none> | name isa abbr | Should be identical to Class_name Comma-separated list of (fully-qualified) class names from which this class is derived. Short version of name for use in database
attribute | class | name abbr type key_type val_type list hash default | The name of the attribute, all lower-case Short version of name for use in database Either the database type or the (fully-qualified) class name if this is an embedded object attribute, unless hash is defined type of the key if hash is defined (may _not_ be a class name) type of the value if hash is defined (may be a class name) 1 if the attribute is a list 1 if the attribute is a hash initial value of the attribute, if any (only if list and hash are not defined)
method | class | name | The name of the method, all lower-case
class-method | class | name | The name of the class method, all lower-case
constructor | class | name | The name of the constructor, all lower-case
param | method, class-method, constructor | name type pos | The name of the parameter, all lower-case Either "scalar" or "array" Number indicating which parameter this is on the stack
em | <any> | <none> | Emphasizes the enclosed text (format)

3.2.1

A sample written description of a hypothetical class:

Let’s say we have a new upcoming project (codenamed "Djakarta") and we determine that we have a need to define a class to represent companies with headquarters in the United States. Suppose we have a base-class which we may inherit from (Let’s say the ‘Djakarta::corporation’ class which describes international corporations). From our analysis, we realize that we have specific characteristics which we wish to keep regarding each of these US companies that is not necessarily already found in our base class such as:

- company name.
- Tax Identification Number (TIN) - [unique identifier provided by the U.S. government (IRS)].
- USA address of headquarters.
- Exporter of Goods (outside of the USA)?[Y/N].
- Date company incorporated.
- a list of products produced by the company.
- a list of products and their associated product-codes.

The type of each of these variable attributes must be decided when creating the pox to define a class. The five major types recognized in the pox file are: numbers, strings, bits, dates and objects.

Our analysis also leads us to believe that Djakarta will need a way to perform the following operations:

- Obtain a list of current employees for the US company having a specific TIN.
- Obtain a list of subsidiaries of the US company from the primary company’s TIN.
- Obtain the New York Stock Exchange acronym for the US company if traded on NYSE using TIN.

All of the aforementioned class attributes and class methods can easily be represented in a pox file which we’ll create to describe our class. In order to continue with our example, let’s call our new class "Us_company". If we were to represent this new class using pox, what do you suppose our pox file would look like? We’ll show you a sample pox for the "Us_company" class on the next page.

3.2.2 A sample pox description of a hypothetical class ("Us_company.pox"):

<?version '$Revision: 1.1.1.1 $'?>

<class name=‘Us_company’ isa=‘Djakarta::Corporation’ abbr=‘usco’>

This United States Company class inherits from the Corporation class. This

class represents American companies that the Djakarta project will monitor.

<attribute name='Company_name' type=‘varchar(255)’>

This is the name of the Company headquartered in the United States.

</attribute>

<attribute name='Company_tin' type=‘char(11)’ abbr=‘emplr_id’>

Unique Tax identification number (assigned by US gov’t/IRS). (e.g. ‘123-45-0987’)

</attribute>

<attribute name=‘Usa_Street_address’ type=‘varchar(255)’>

This is the street address of company headquarters. (e.g. ‘125 Main Street’).

</attribute>

<attribute name=‘Usa_City’ type=‘varchar(80)’>

This is the City where the company’s headquarters is located.

</attribute>

<attribute name=‘Usa_State’ type=‘char(2)’ abbr=‘ST’>

This is the State (abbreviated; e.g. "NY") where the company’s headquarters is located.

</attribute>

<attribute name=‘Usa_Zipcode’ type=‘char(9)’ abbr=‘Zip’>

This is the zipcode for the company’s headquarters.

</attribute>

<attribute name=‘Us_Exporter’ type=‘bit’ default=‘0’>

Boolean bit-flag to distinguish exporters (ship to outside US) from non-exporters.

</attribute>

<attribute name=‘Date_incorporated type=‘datetime’>

This is the date the company was incorporated.

</attribute>

<attribute name=‘Product_list’ list=‘1’ type='Djakarta::Product'>

List of products the Company produces. (Empty list for "no products".)

</attribute>

<attribute name=‘Product_id_and_detail’ key_type=‘char(10)’ val_type=‘Djakarta::Product’ hash=‘1’>

Hash [keyed on product-id] of Product objects. Useful in retrieving specific product information

such as description, price, in-stock inventory, etc.

</attribute>

<class-method name='Current_Employees'>

<param name='Company_tin' type='char(10)' pos='1'>

A Company_tin (tax id number) is passed as a parameter to this method.

</param>

Method returns list of current employees for the Company-id passed in parm.

</method>

<class-method name='Subsidiaries'>

<param name='Company_tin' type='char(10)' pos='1'>

A Company_tin (tax id number) is passed as a parameter to this method.

</param>

Method returns list of subsidiary companies for the Company-id passed in parm.

</method>

<method name=‘NYSE_Trading_Information’>

<param name='Company_tin' type='char(10)' pos='1'>

An Company_tin (tax id number) is passed as a parameter to this method.

</param>

Returns the New York Stock Exchange acronym for US Company with TIN passed.

</method>

</class>

Once a developer has created a pox file to describe a class (such as the "Us_company" class on the previous page) several utilities can be invoked which use pox/poxen as input. These utilities are described in detail later in this document. Prior to invoking these utilities, other preparations must be made such as the setting of several environment variables.

3.3 Setting Environment Variables prior to processing poxen.

Several environment variables need to be set for each individual system before that system is able to use POP. These variables will use an environment.template file and the create_environment program to create an environment shell script. This script must be sourced prior to using the system. Please refer to the

PPS Developer’s Guide for more information regarding the setting and use of the required POP environment variables. The following table outlines the names of the various POP environment variables and their purpose.

Environment Variable | Purpose
POXLIB | Specifies the directory where the poxen reside (especially those to be inherited from.)
SYBASE | Specifies the location of the sybase client library (e.g. "/sybase/server11p" on albsun4 or "/opt/sybase" on albsun9.)
DBI_DRIVER | Specifies which DBI driver to use. (Should be "Sybase" for current POP processing.)
DB_SERVER | Specifies which database server to use. (Currently "albsun2_sql11_dev" for the development server and "albsun8_sql11_prd" for the production server.)
DB_DB | Specifies which database to use in the DB_SERVER server. (For fez, "fez_dbdata_dev" in development, "fez_dbdata_prd" in production.)
DB_USER | Specifies user name to connect to database as.
DB_PASSWD | Specifies password for DB_USER
POX_SYSTEM | Specifies system name with first letter always capitalized. (For fez, would be "Fez".)

3.4

Understanding how the pox utilities parse their parameters

The major pox utilities (poxhtml, poxperl and poxdb) all use the same code to parse the parameters they are passed. This section will take advantage of that fact and explain the way arguments are handled for these utilities all at once. The major pox utilities accept parameters primarily in the following ways:

- a matching set of files (one input [pox] file & a corresponding output file[utility determines format].)
- a matching set of directories (one input directory [poxen-filled] & one output directory.)
- multiple matching sets of files (n input [pox] files & n corresponding output files.)

In the case of arguments passed in a matching set of files, consider the following example:

poxhtml Us_company.pox -out Us_company.html

When we dissect the example we find the utility name ("poxhtml"), followed by the name of a single pox file ("Us_company.pox"), which is followed by the switch ("-out"), which is in turn followed by the name of the requested output file ("Us_company.html", in this case). In this example, the utility poxhtml will take the Us_company.pox file found in the current directory and from the pox and comments found inside it will generate a documentation file in html format which will be placed in the Us_company.html output file.

In the case of arguments passed in a matching set of directories, consider the following example:

poxperl Djakarta/pox/ -out Djakarta/lib

When we dissect the example we find the utility name ("poxperl"), followed by the name of a poxen directory ("Djakarta/pox") which is followed by the switch ("-out"), which is in turn followed by the name of the requested output directory ("Djakarta/lib", in this case). In this example, each individual pox file that the poxperl utility finds in the input directory will be processed and will have a corresponding like-named output file placed in the output directory.

In the case of arguments passed as multiple matching sets of files, consider the following example:

poxdb Employee.pox -out Employee.schema Car.pox -out Car.schema

When we dissect the example we find the utility name ("poxdb"), followed by the name of the first pox input file ("Employee.pox") which is followed by the switch ("-out"), which is in turn followed by the name of the first requested output file ("Employee.schema", in this case). This matched set of files is then followed by another pox input file ("Car.pox") which is followed by another switch ("-out") and the corresponding output file ("Car.schema" in this case.) In this example, each individual pox file that the poxdb utility finds as an input file parameter (i.e. not preceded by an "-out" switch) will be processed and will have an output file placed in the corresponding output file (i.e. the parameter which follows the previous input file and "-out" switch.) Note that any number of multiple matching sets of files can be passed as parameters as long as the arguments are passed in the scheme illustrated by the example above.

3.5 Creating documentation using "poxhtml"

A utility named "poxhtml" is used by PPS developers to create documentation in html format. This utility should be invoked from the root of the developer’s working directory. "Poxhtml" takes one or more pox files as input and creates a corresponding html output file for each pox file found as input. (Please see the section on "Understanding how the pox utilities parse their parameters" for examples on how to invoke this utility with parameters.) Each html output file will contain the name of the class encountered in the pox file at the highest heading level. Any classes from which this class is derived will also be found in the html output file. The name of each base class will be a hyperlink to the page for that class. Sections will be created for attributes, methods, class-methods and constructors. Underneath each of the aforementioned sections will be the corresponding elements of that type (inherited or otherwise). Also, any types which are actually class names will be hyperlinks to the page for that class.

3.6 Creating Perl modules using "poxperl"

A utility named "poxperl" takes pox file(s) as input and converts each class definition encountered into a perl module which begins the implementation of that class. The developer is responsible for making sure that POP environment variables are set correctly for the current project prior to running "poxperl". (Please see the section on "Setting Environment Variables prior to processing poxen".) The output perl module is created but could be considered more of a "skeleton" in that it is up to the developer to modify the module in such a way as to fully implement the class.. (i.e. methods found in pox files will contain parameters for a method but would not necessarily contain the perl code for the method.) One perl module will be created for each pox file found as an input parameter. (Please see the section on "Understanding how the pox utilities parse their parameters" for examples on how to invoke this utility with parameters.)

3.7 Creating database schema using "poxdb"

A utility named "poxdb" takes pox file(s) as input and converts each class definition encountered into the schemata necessary to provide object persistence for each class. One schema file will be created for each pox input file passed as a parameter. (Please see the section on "Understanding how the pox utilities parse their parameters" for examples on how to invoke this utility with parameters.)

3.8 Using "schemadrop"

A utility named "schemadrop" is used when a developer wishes to drop a particular class or group of classes. Please note that before schema is "dropped" or tables are dropped, responsible developers will consider what data in the database, if any, must be retained. Regardless of the environment (test, certification, or, most notably production) the This utility will drop all tables, indices and stored procedures associated with the schema passed as input. If an error occurs during "schemadrop", a message will be displayed for each error and processing will continue. The "schemadrop" utility can be passed a single schema file or a directory full of schema files (where the asterisk [*] is used as a wildcard symbol meaning "all ‘*.schema’ files found in the specified directory.) When "Schemadrop" is passed an entire directory as a parameter, it will drop all the schema associated with each of the files with "schema" file-extensions. A sample invocation with a single schema file passed as a parameter might be:

schemadrop db/Car.schema

whereas a sample invocation with a directory parameter might be:

schemadrop db/*

3.9

Using "schemaload"

A utility named "schemaload" is used when a developer wishes to incorporate the schema output from the most recent "poxdb" run into the database in the developer’s environment of choice. If an error occurs during "schemaload", a message will be displayed and processing is halted. The developer is then responsible for making corrections to the schema or pox files and re-attempting a "schemaload". The "schemaload" utility can be passed a single schema file or a directory full of schema files (where the asterisk [*] is used as a wildcard symbol meaning "all ‘*.schema’ files found in the specified directory.) A sample invocation with a single schema file passed as a parameter might be:

schemaload db/Car.schema

which will load the schema (Car.schema, in this case) into the database specified by the current values in the environment variables whereas a sample invocation with a directory parameter might be:

schemaload db/*

which will load the schema (all schema files found in the db directory, in this case) into the database specified by the current values in the environment variables.

3.10 Merging pox changes with an updated perl module

In the event that developers find the need to change pox/poxen after they have already modified the perl modules output by "poxperl" they must be careful not to lose the perl code they’ve developed. We recommend that the developer perform the following steps to ensure that no code is lost:

1. Create original pox file to describe and define a class.
2. Perform a "check-in" of the pox file into the CVS source code repository. (cvs "add", then "commit".)
3. Use the poxperl utility to generate a "skeleton" perl module. (e.g. "Us_company.pm").
4. Modify the perl module expanding methods to attempt to fully implement the class.
5. Perform a "check-in" of the perl module into the CVS source code repository. (cvs "add", then "commit")
6. If changes are deemed necessary at this point, then change the pox file (e.g."Us_company.pox") as you have all of your work saved in CVS.
7. Perform a "check-in" of the new pox file into the CVS source code repository. (cvs "add", then "commit" and the use of a version tag is recommended here.)
8. Run poxperl again (this time on the new pox file.)
9. Check the old-version of the perl module out of CVS into a temporary file (e.g."Temp_Us_co.pm").
10. Run a UNIX "diff" to obtain the difference between the temporary file and the new perl module and pipe it to a "patch" file.
11. Run a UNIX "patch" command to patch the patch-file changes into the new perl module code.

This process should save you from losing valuable perl code.

3.11 Perl class code required when you add an attribute to your class

When adding an attribute, you must create an accessor for it and add

it to the initialize method. These are the rules you must follow,

based on the type of the attribute.

In the examples which follow, the

attribute name will be 'attr', the system name will be 'System' and

the class for which we are adding the 'attr' attribute will be

'Class'.

3.11.1 Scalar non-object

ACCESSOR:

=head2 ACCESSOR

Title: System::Class::attr

Desc: Description of 'attr' attribute

=cut

sub attr {

my $this = shift;

if (@_) {

my $obj = shift;

$this->{'attr'} = $obj;

}

$this->{'attr'};

}

INITIALIZE:

$this->{'attr'} = '';

---

3.11.2 Scalar object

This example uses a scalar embedded (has-a) object of class ‘System::Foo’

ACCESSOR:

=head2 ACCESSOR

Title: System::Class::attr

Desc: Description of 'attr' attribute

=cut

sub attr {

my $this = shift;

if (@_) {

my $obj = shift;

unless (ref($obj) && UNIVERSAL::isa($obj, 'System::Foo')) {

croak "[$obj] is not a System::Foo object";

}

$this->{'attr'} = \$obj;

}

${$this->{'attr'}};

}

INITIALIZE:

$this->{'attr'} = \do{my $a};

---

3.11.3 List of non-objects

This example assumes a list of type ‘int’

ACCESSOR:

=head2 ACCESSOR

Title: System::Class::attr

Desc: Description of 'attr' attribute

=cut

sub attr {

my $this = shift;

if (@_) {

$this->{'attr'} = [@_];

}

wantarray ? @{$this->{'attr'}} : $this->{'attr'};

}

INITIALIZE:

$this->{'attr'} =

$this->_POP__Persistent_list_from_db('int', 'attr');

3.11.4 List of objects

This example uses a list of embedded (has-a) objects of class ‘System::Foo’

ACCESSOR:

=head2 ACCESSOR

Title: System::Class::attr

Desc: Description of 'attr' attribute

=cut

sub attr {

my $this = shift;

if (@_) {

foreach (@_) {

unless (ref($_) && UNIVERSAL::isa($_, 'System::Foo')) {

croak "[$_] is not a System::Foo object";

}

}

$this->{'attr'} = [@_];

}

wantarray ? @{$this->{'attr'}} : $this->{'attr'};

}

INITIALIZE:

$this->{'attr'} =

$this->_POP__Persistent_list_from_db('System::Foo', 'attr');

3.11.5 Hash of non-objects

This example uses a hash of strings (char 30)

ACCESSOR:

=head2 ACCESSOR

Title: System::Class::attr

Desc: Description of 'attr' attribute

=cut

sub attr {

my $this = shift;

if (@_) {

my %hash = @_;

$this->{'attr'} = \%hash;

}

wantarray ? %{$this->{'attr'}} : $this->{'attr'};

}

INITIALIZE:

$this->{'attr'} =

$this->_POP__Persistent_hash_from_db('char(30)', 'attr', {});

---

3.11.6 Hash of objects

This example uses a hash of embedded objects, of type 'System::Foo'

ACCESSOR:

=head2 ACCESSOR

Title: System::Class::attr

Desc: Description of 'attr' attribute

=cut

sub attr {

my $this = shift;

if (@_) {

my %hash = @_;

while (my($k,$v) = each %hash) {

unless (ref($v) && UNIVERSAL::isa($v, 'System::Foo') {

croak "[$v] is not a System::Foo object";

}

}

$this->{'attr'} = \%hash;

}

wantarray ? %{$this->{'attr'}} : $this->{'attr'};

}

INITIALIZE:

$this->{'attr'} =

$this->_POP__Persistent_hash_from_db('System::Foo', 'attr', {});

4. POP processing