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

NAME

JOAP::Server::Class - Base Class for JOAP Server-Side Classes and Instances

SYNOPSIS

    package MyPerson;
    use base qw(JOAP::Server::Class);
    use Error;

    # define class description

    MyPerson->Description(<<'END_OF_DESCRIPTION');
    Basic info on a person.
    END_OF_DESCRIPTION

    # define class attributes

    MyPerson->Attributes (
        {
            given_name => {
                type => 'string',
                required => 1,
                desc => 'Given name of the person.'
            },

            family_name => {
                type => 'string',
                required => 1,
                desc => 'Family name of the person.'
            },

            birthdate => {
                type => 'dateTime.iso8601',
                required => 1,
                desc => 'birthdate of person in GMT'
            },

            age => {
                type => 'i4',
                writable => 0,
                desc => 'Age in years (rounded down) of person at current time',
            },

            species => {
                type => 'string',
                writable => 0,
                allocation => 'class',
                desc => 'species of people'
            },
        });

    # specify methods

    MyPerson->Methods (
        {
            walk => {
                returnType => 'boolean',
                params => [
                    {
                        name => 'steps',
                          type => 'i4',
                          desc => 'how many steps forward to walk, fault if less than zero'
                    }
                ],
                desc => 'Walk forward \'steps\' steps'},
        });

    # specify the class ID

    MyPerson->Id(['family_name', 'given_name']);

    # specify class variables

    our $species = 'homo sapiens';

    # an accessor for an attribute

    sub age {

        my $self = shift;
        my $bd = $self->birthdate;
        my @now = gmtime;

        my @then = JOAP->datetime_to_array($bd);

        my ($y, $m, $d) = ($then[5], $then[4], $then[3]);

        my $age = $now[5] - $y;

        if (($now[4] > $m) ||
            ($now[4] == $m && $now[3] >= $d))
        {
            $age++;
        }

        return $age;
    }

    # an instance method

    sub walk {

        my $self = shift;
        my $steps = shift;

        if ($steps < 0) {
            throw Error::Simple("Never go back.", 5440);
        }

        for (my $i = 0; $i < $steps; $i++) {
            $self->step();
        }

        return 1;
    }

    1;                          # gotta return 1

ABSTRACT

This is an abstract superclass for creating Perl classes that are servable through JOAP.

DESCRIPTION

Well, I haven't been looking forward to writing this POD, but here we go.

JOAP::Server::Class is the pulsing heart of the JOAP server-side universe. You use it to create your own JOAP-servable classes, and things should just work.

The key part of this framework is that you define your class's structure -- its attributes, methods, and superclasses -- using class mutators in your class module. The server framework uses this structural definition to expose your class to the Jabber network, and handles all JOAP and XML-RPC messages for you. It routes requests for attributes and methods to the appropriate part of your class automatically, and it will create data, and methods, in the right places if you just leave everything at the defaults.

The basic model is that your Perl class becomes a JOAP class, and each Perl instance becomes a JOAP instance. Instance data is stored in the instance, and class data is stored in the class. It's pretty simple.

There's also an interface that's exposed to object servers; it's not documented here (yet).

Class Methods

This section discusses the class methods you need to call to define your class. Usually you just call them straight from the class module, as shown above in the synopsis.

Description($string)

Sets the human-readable description of the class.

Attributes($hashref)

This sets the publicly available attributes for the class. $hashref is a reference to a hashtable mapping attribute names to attribute descriptors. See JOAP::Descriptors for the format of this data structure.

Besides the fields listed there, the attribute descriptor can also contain the following fields:

getter

This is the name of, or a reference to, a method that returns the value of the attribute. If no getter is defined, the method in this package with the same name as the attribute is used. If no such method is defined, an autoloaded method is defined at runtime (see "Autoloaded Accessors" below for details).

setter

This is the name of, or a reference to, a method that sets the value of the attribute. If no setter is defined, the method in this package with the same name as the attribute is used. If no such method is defined, an autoloaded method is defined at runtime (see "Autoloaded Accessors" below for details).

accessor

This is the name of, or a reference to, a method that acts as both 'getter' and 'setter'.

Methods($hashref)

This sets the publicly available methods for the class. $hashref is a reference to a hashtable mapping method names to method descriptors; see JOAP::Descriptors for the format of method descriptors.

As well as the fields described normally for method descriptors, the following fields are also used:

function

This is the name of, or reference to, a function that acts as this method. If the field is not provided, the function with the same name in this package will be used.

Superclasses($arrayref)

This sets the visible superclasses for the class. $arrayref is a reference to an array of strings containing the JOAP addresses of all superclasses of the class. See JOAP::Addresses for the format of JOAP addresses.

Id($arrayref)

This sets the attributes that will be used to construct instance IDs for instances of this class. $arrayref is a reference to an array of attribute names. The IDs will be used in the order defined.

If IdFormat (see below) is defined, that printf-style format string will be used to construct the instance of the object, with the values of the listed attributes as parameters. Otherwise, a string will be constructed joining the values of each attribute with the separator defined by Separator (see below).

The combination of the attributes used in the Id array should be sufficient to uniquely identify an instance.

IdFormat($fmt)

Sets the string used for formatting the instance IDs. This is a "printf" in perlfunc format string. The value of each attribute in the array will be given, in order, as parameters.

Note that support for this feature is spotty right now; using Separator below is your safest bet for the near future.

Separator($sep)

Sets the string used to separate attributes in the instance ID. Defaults to ',', but you may want to set it to another value for classes where, say, a comma may appear in the attribute data.

Container Interface

This class also has an interface that containers can use to retrieve instances of the class.

Package->get($instid)

This method returns the instance object that has the given instance ID, or undef if no such instance exists.

Storage Interface

By default, instances are stored in memory in a hashtable that maps instance IDs to the instances themselves. This is pretty losey, doesn't persist the instances through program invocations, and could stand a lot of work. The interface used internally by JOAP::Server::Class to retrieve instances looks like this:

Package->get_instance($instid)

Returns the instance that has instance ID $instid, or undef if such an instance doesn't exist.

Package->set_instance($instid, $inst)

Maps the instance $inst to instance ID $instid.

Package->delete_instance($instid)

Removes the instance with instance ID $instid from the storage map.

Autoloaded Accessors

If a getter or setter is not defined for an attribute named in the Attributes map, the JOAP server libraries try to use a function by the same name as a Perl method to retrieve or set the attribute. You can use this for attributes that are calculated from the values of other attributes, like the age attribute in the synopsis above.

If no Perl method by the same name is defined, the library creates a method to act as an accessor. This happens when the attribute is first used.

The default autoloaded accessor for instance attributes will store the attribute value as a field in the instance. For class attributes, the value will be stored as a symbol in the class package. The $species attribute in the synopsis is an example of a class attribute in the package's namespace.

It's generally better practice to use accessors for attributes in your custom code, rather than using the instance fields or class variables directly.

Custom Accessors

As mentioned above, you can define custom accessors if simple data storage is not sufficient, or if you need to define side-effects from setting or getting an attribute. (For example, the synopsis above shows an age attribute defined with a custom accessor that calculates the value from the birthdate attribute. An alternative would be a custom accessor for birthdate that calculates and sets the value of age whenever birthdate is updated.)

Accessors will be called like:

    $self->accessor($value)

...for setting the value, and:

    $value = $self->accessor

...for getting the value. $self will be an instance of the class for attributes with allocation 'instance', and the class itself for attributes with allocation 'class'.

Accessors will never be called to set the value of an attribute if that attribute has its writable flag set to 0.

Custom Methods

If your class exposes methods for public use, you need to define custom code for those methods. Your method will be called like:

    $return_value = $self->method($param1, $param2, ...)

Here, $self is either an instance of this class, if the method allocation is 'instance', or the class itself, if the method allocation is 'class'. The parameters will be the parameters defined in the params field, in order.

Your method will never be called with parameters of the wrong type, or with the wrong number of parameters. That's handled at the library level.

As mentioned above, for each method, you can either define an eponymous method in the package, or you can use the function field of the method descriptor to map another function in as the method.

If there are problems with your method, you can throw an Error exception as defined in Error. The value and text of the Error will be mapped to the faultCode and faultString in the resulting XML-RPC fault.

Data Marshalling

In your custom code, you shouldn't normally have to worry about JOAP's funky data types in your custom code. All parameters and attribute values your code receives as input will already have been marshalled to native Perl types. You can return values as Perl types, and they'll be marshalled to the correct JOAP data type.

Some caveats, though:

array

Arrays are handled by reference. You should return references to arrays as return values, and you'll receive references to arrays as input.

struct

Structs are marshalled to hash references. You should return references to hashes as return values, and you'll receive references to hashes as input.

dateTime.iso8601

These values are not marshalled into any native Perl type, since there's not really a good native type to marshall them into. Instead, they come in as ISO 8601 formatted strings. You can use the JOAP-datetime_to_array> method to convert this to an array like the one returned by "gmtime" in perlfunc. You can return references to gmtime-like arrays, or just integers in seconds-since-the-epoch format (as returned by "time" in perfunc), or as formatted strings.

EXPORT

None by default.

BUGS

This documentation is woefully insufficient.

There's currently no persistence built in to this class, and there's no documentation on how to implement your own persistence (although it's possible).

There's no documentation on how to build on-the-fly classes that act as a gateway to non-JOAP object systems.

SEE ALSO

See JOAP for general information about JOAP as well as contact information for the author.

See Error for how to throw Error exceptions.

See JOAP::Server::Object for a bit more information about how this class works.

See JOAP::Server for defining object servers.

AUTHOR

Evan Prodromou, <evan@prodromou.san-francisco.ca.us>

COPYRIGHT AND LICENSE

Copyright (c) 2003, Evan Prodromou <evan@prodromou.san-francisco.ca.us>

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA