This is Info file pm.info, produced by Makeinfo version 1.68 from the
input file bigpm.texi.
File: pm.info, Node: SOAP/Transport/HTTP/AutoInvoke/Client, Next: SOAP/Transport/HTTP/AutoInvoke/Server, Prev: SOAP/Transport/HTTP/Apache, Up: Module List
Automarshall methods for Perl SOAP
**********************************
NAME
====
SOAP::AutoInvoke - Automarshall methods for Perl SOAP
SYNOPSIS
========
#!/usr/bin/perl -w
#
# Client example that goes with server example
# in SOAP::Transport::HTTP::AutoInvoke
#
use strict;
package Calculator;
use base qw( SOAP::AutoInvoke );
package main;
my $calc = new Calculator;
print "sum = ", $calc->add ( 1, 2, 3 ), "\n";
DESCRIPTION
===========
The intention of SOAP::AutoInvoke is to allow a SOAP client to use a
remote class as if it were local. The remote package is treated as local
with a declaration like:
package MyClass;
use base qw( SOAP::AutoInvoke );
The SOAP::AutoInvoke base class will "Autoload" methods called from an
instance of "MyClass", send it to the server side, and return the results
to the caller's space.
Provided Methods
----------------
new:
* * The 'new' method may be called with option arguments to reset
variables from the defaults.
my $class = new MyClass (
_soap_host => 'anywhere.com',
_soap_port => 80,
_soap_endpoint => 'soapx?class=OtherClass',
_soap_method_uri => 'urn:com-name-your'
);
It is advisable to set the package defaults at installation time in
the SOAP/Transport/HTTP/AutoInvoke/Client.pm (this) file. The
variables may also be reset after instantiation with the 'set'
methods.
The '_soap_' variable is relevant only to the local instantiation of
"MyClass". The remote instantiation will call "new" with any
arguments you have passed to the local instantiation that did not
begin with '_soap_':
my $class = new MyClass (
_soap_host => 'anywhere.com',
arg1,
arg2,
@arg3,
arg4 => $value,
:
);
This works so long as the data types being passed are something the
SOAP package can serialize. SOAP::AutoInvoke can send and receive
simple arrays.
To reset the name of the "new" to be called remotely:
my $class = new MyClass (
:
_soap_new_method => 'create',
:
);
To not call any new method remotely:
my $class = new MyClass (
:
_soap_new_method => undef,
:
);
*_soap_get_host*:
returns the contents of $class->{_soap_host}.
*_soap_set_host*:
sets the contents of $class->{_soap_host}.
*_soap_get_port*:
returns the contents of $class->{_soap_port}.
*_soap_set_port*:
sets the contents of $class->{_soap_port}.
*_soap_get_endpoint*:
returns the contents of $class->{_soap_endpoint}.
*_soap_set_endpoint*:
sets the contents of $class->{_soap_endpoint}.
*_soap_get_method_uri*:
returns the contents of $class->{_soap_method_uri}.
*_soap_set_method_uri*:
sets the contents of $class->{_soap_method_uri}.
*_soap_get_new_args*:
returns the contents of $class->{_soap_new_args}.
*_soap_set_new_args*:
sets the contents of $class->{_soap_new_args}.
*_soap_get_new_method*:
returns the contents of $class->{_soap_new_method}.
*_soap_set_new_method*:
sets the contents of $class->{_soap_new_method}. The default is
"new".
DEPENDENCIES
============
SOAP-0.28 Data::Dumper
AUTHOR
======
Daniel Yacob, `yacob@rcn.com|mailto:yacob@rcn.com' in this node
SEE ALSO
========
perl(1). SOAP(3). SOAP::Transport::HTTP::AutoInvoke(3).
File: pm.info, Node: SOAP/Transport/HTTP/AutoInvoke/Server, Next: SOAP/Transport/HTTP/CGI, Prev: SOAP/Transport/HTTP/AutoInvoke/Client, Up: Module List
Automarshall methods for Perl SOAP
**********************************
NAME
====
SOAP::Transport::HTTP::AutoInvoke - Automarshall methods for Perl SOAP
SYNOPSIS
========
package Apache::SoapServer;
use strict;
use SOAP::Transport::HTTP::Apache; # must be the provided Apache.pm!
use SOAP::Transport::HTTP::AutoInvoke; # import "auto_invoke" dispatcher
sub handler {
my $safe_classes ={
ClassA => undef, # uses default dispatcher
ClassB => undef, # uses default dispatcher
Calculator => \&auto_invoke, # uses specified dispatcher
ClassC => undef, # uses default dispatcher
ClassD => \&myDispatcher, # uses specified dispatcher
};
SOAP::Transport::HTTP::Apache->handler($safe_classes);
}
1;
DESCRIPTION
===========
SOAP::Transport::HTTP::AutoInvoke provides the dispatch subroutine
"auto_invoke" to handle class instantiation and method invocation that
were called with a client created with
SOAP::Transport::ActiveWorks::AutoInvoke::Client.
DEPENDENCIES
============
SOAP-0.28 SOAP::AutoInvoke Data::Dumper
AUTHOR
======
Daniel Yacob, `yacob@rcn.com|mailto:yacob@rcn.com' in this node
SEE ALSO
========
perl(1). SOAP(3). SOAP::AutoInvoke(3).
File: pm.info, Node: SOAP/Transport/HTTP/CGI, Next: SOAP/Transport/HTTP/Client, Prev: SOAP/Transport/HTTP/AutoInvoke/Server, Up: Module List
Generic SOAP CGI handler
************************
NAME
====
SOAP::Transport::HTTP::CGI - Generic SOAP CGI handler
SYNOPSIS
========
Use this class to expose SOAP endpoints using vanilla CGI. Here's an
example SOAP endpoint exposed using this class:
package ServerDemo;
use strict;
use SOAP::Transport::HTTP::CGI;
sub handler {
my $safe_classes = {
Calculator => undef,
};
SOAP::Transport::HTTP::CGI->handler($safe_classes);
}
1;
(I leave it up to you to figure out how to get Perl scripts to run as
CGI scripts - please see your Perl docs for details)
DESCRIPTION
===========
This class encapsulates the details of hooking up to CGI, and then
calls SOAP::Transport::HTTP::Server to do the SOAP-specific stuff. This
way the Server class can be reused with any web server configuration
(including mod_perl), by simply composing it with a different front-end
(for instance, SOAP::Transport::HTTP::Apache, for instance.
handler(SafeClassHash, OptionalDispatcher)
------------------------------------------
This is the only method on the class, and you must pass a hash
reference whose keys contain the collection of classes that may be invoked
at this endpoint. If you specify class FooBar in this list, for instance,
and a client sends a SOAP request to http://yourserver/soap?class=FooBar,
then the SOAP::Transport::HTTP::Server class will eventually attempt to
load FooBar.pm, instatiate a FooBar, and call its handle_request function
(see SOAP::Transport::HTTP::Server for more detail). If you don't include
a class in this hash, SOAP/Perl won't run it. I promise.
By the way, only the keys in this hash are important, the values are
ignored.
Also, nothing is stopping you from messing around with the response
yourself if you'd like to add some headers or whatever; you can always
call print() dump more headers to STDOUT. Just make sure you finish what
you're doing before you return to SOAP::Transport::HTTP::Server, because
at that point the response is marshaled and sent back.
See SOAP::Transport::HTTP::Server for details on the OptionalDispatcher
parameter.
DEPENDENCIES
============
SOAP::Transport::HTTP::Server
AUTHOR
======
Keith Brown
File: pm.info, Node: SOAP/Transport/HTTP/Client, Next: SOAP/Transport/HTTP/Server, Prev: SOAP/Transport/HTTP/CGI, Up: Module List
Client side HTTP support for SOAP/Perl
**************************************
NAME
====
SOAP::Transport::HTTP::Client - Client side HTTP support for SOAP/Perl
SYNOPSIS
========
use SOAP::Transport::HTTP::Client;
DESCRIPTION
===========
Forthcoming...
DEPENDENCIES
============
LWP::UserAgent SOAP::Defs
AUTHOR
======
Keith Brown
SEE ALSO
========
File: pm.info, Node: SOAP/Transport/HTTP/Server, Next: SOAP/Transport/HTTPX, Prev: SOAP/Transport/HTTP/Client, Up: Module List
Server side HTTP support for SOAP/Perl
**************************************
NAME
====
SOAP::Transport::HTTP::Server - Server side HTTP support for SOAP/Perl
SYNOPSIS
========
use SOAP::Transport::HTTP::Server;
DESCRIPTION
===========
This class provides all the HTTP related smarts for a SOAP server,
independent of what web server it's attached to. It exposes a single
function (that you'll never call, unless you're adapting SOAP/Perl to a
new web server environment) that provides a set of function pointers for
doing various things, like getting information about the request and
sending response headers and content.
What *is* important to know about this class is what it expects of you
if you want to handle SOAP requests. You must implement your class such
that it can be created via new() with no arguments, and you must implement
a single function:
handle_request(HeaderArray, Body, EnvelopeMaker)
------------------------------------------------
The first two arguments are the input, an array of header objects
(which may be empty if no headers were sent), a single Body object, and a
third object to allow you to send a response.
See EnvelopeMaker to learn how to send a response (this is the same
class used by a client to send the request, so if you know how to do that,
you're cooking with gas).
HeaderArray and Body are today simply hash references, but in the
future, they may be blessed object references.
If you want to customize this call-dispatching mechanism, you may pass
a code reference for the OptionalDispatcher argument.
The OptionalDispatcher argument allows you to override the default
dispatching behavior with your own code. This should reference a
subroutine with the following signature:
custom_dispatcher(RequestedClass, HeaderArray, Body, EnvelopeMaker)
-------------------------------------------------------------------
sub my_dispatcher { my ($requested_class, $headers, $body, $em) =
@_;
# here's a simple example that converts the request
# into a method call (it doesn't deal with headers though)
my $method_name = $body->{soap_typename};
require $requested_class . '.pm';
my $retval = $requested_class->$method_name(%$body);
$em->set_body($body->{soap_typeuri}, $method_name . 'Response',
0, {return => $retval});
}
The above example handles each request by invoking a class-level method
on the requested class.
DEPENDENCIES
============
SOAP::Defs SOAP::Parser SOAP::EnvelopeMaker
AUTHOR
======
Keith Brown
SEE ALSO
========
SOAP::Transport::HTTP::EnvelopeMaker SOAP::Transport::HTTP::Apache
File: pm.info, Node: SOAP/Transport/HTTPX, Next: SOAP/Transport/IO, Prev: SOAP/Transport/HTTP/Server, Up: Module List
Server/Client side HTTP Smart Proxy for SOAP::Lite
**************************************************
NAME
====
SOAP::Transport::HTTPX - Server/Client side HTTP Smart Proxy for
SOAP::Lite
SYNOPSIS
========
use SOAP::Lite +autodispatch =>
uri => 'urn:',
proxy => 'httpx://my.smart.server/soap',
on_fault => sub { my($soap, $res) = @_;
die ref $res ? $res->faultdetail : $soap->transport->status, "\n";
}
;
print Hello->SOAP::echo ( 'Paul' ), "\n";
DESCRIPTION
===========
The SmartProxy package is intended for use in a multi-server setting
where one or more servers may not be directly accessible to client side
scripts. The SmartProxy package makes request redirection and forwarding
on a per class basis easy. Client scripts need not know which server is
appropriate for a specific request and may make all requests from a single
master server which can be relied upon to redirect clients to the server
currently fulfilling a given request. The relieves a maintenance burden
on the client side. The server may also redirect clients to a new class
name or fully qualified action URI (methods and arguments are assumed to
remain constant however).
DEPENDENCIES
============
The SOAP-Lite package.
SEE ALSO
========
See SOAP::Transport::HTTP
COPYRIGHT
=========
Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
AUTHOR
======
Daniel Yacob (yacob@rcn.com)
Paul Kulchenko (paulclinger@yahoo.com)
File: pm.info, Node: SOAP/Transport/IO, Next: SOAP/Transport/LOCAL, Prev: SOAP/Transport/HTTPX, Up: Module List
Server side IO support for SOAP::Lite
*************************************
NAME
====
SOAP::Transport::IO - Server side IO support for SOAP::Lite
SYNOPSIS
========
use SOAP::Transport::IO;
SOAP::Transport::IO::Server
# you may specify as parameters for new():
# -> new( in => 'in_file_name' [, out => 'out_file_name'] )
# -> new( in => IN_HANDLE [, out => OUT_HANDLE] )
# -> new( in => *IN_HANDLE [, out => *OUT_HANDLE] )
# -> new( in => \*IN_HANDLE [, out => \*OUT_HANDLE] )
# -- OR --
# any combinations
# -> new( in => *STDIN, out => 'out_file_name' )
# -> new( in => 'in_file_name', => \*OUT_HANDLE )
# -- OR --
# use in() and/or out() methods
# -> in( *STDIN ) -> out( *STDOUT )
# -- OR --
# use default (when nothing specified):
# in => *STDIN, out => *STDOUT
# don't forget, if you want to accept parameters from command line
# \*HANDLER will be understood literally, so this syntax won't work
# and server will complain
-> new(@ARGV)
# specify path to My/Examples.pm here
-> dispatch_to('/Your/Path/To/Deployed/Modules', 'Module::Name', 'Module::method')
-> handle
;
DESCRIPTION
===========
COPYRIGHT
=========
Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
AUTHOR
======
Paul Kulchenko (paulclinger@yahoo.com)
File: pm.info, Node: SOAP/Transport/LOCAL, Next: SOAP/Transport/MAILTO, Prev: SOAP/Transport/IO, Up: Module List
Client side no-transport support for SOAP::Lite
***********************************************
NAME
====
SOAP::Transport::LOCAL - Client side no-transport support for SOAP::Lite
SYNOPSIS
========
DESCRIPTION
===========
COPYRIGHT
=========
Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
AUTHOR
======
Paul Kulchenko (paulclinger@yahoo.com)
File: pm.info, Node: SOAP/Transport/MAILTO, Next: SOAP/Transport/POP3, Prev: SOAP/Transport/LOCAL, Up: Module List
Client side SMTP/sendmail support for SOAP::Lite
************************************************
NAME
====
SOAP::Transport::MAILTO - Client side SMTP/sendmail support for
SOAP::Lite
SYNOPSIS
========
use SOAP::Lite;
SOAP::Lite
-> uri('http://soaplite.com/My/Examples')
-> proxy('mailto:destination.email@address', smtp => 'smtp.server', From => 'your.email', Subject => 'SOAP message')
# or
# -> proxy('mailto:destination.email@address?From=your.email&Subject=SOAP%20message', smtp => 'smtp.server')
# or if you want to send with sendmail
# -> proxy('mailto:destination.email@address?From=your.email&Subject=SOAP%20message')
# or if your sendmail is in undiscoverable place
# -> proxy('mailto:destination.email@address?From=your.email&Subject=SOAP%20message', sendmail => 'command to run your sendmail')
-> getStateName(12)
;
DESCRIPTION
===========
COPYRIGHT
=========
Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
AUTHOR
======
Paul Kulchenko (paulclinger@yahoo.com)
File: pm.info, Node: SOAP/Transport/POP3, Next: SOAP/Transport/TCP, Prev: SOAP/Transport/MAILTO, Up: Module List
Server side POP3 support for SOAP::Lite
***************************************
NAME
====
SOAP::Transport::POP3 - Server side POP3 support for SOAP::Lite
SYNOPSIS
========
use SOAP::Transport::POP3;
my $server = SOAP::Transport::POP3::Server
-> new('pop.mail.server')
# if you want to have all in one place
# -> new('user:password@pop.mail.server')
# specify list of objects-by-reference here
-> objects_by_reference(qw(My::PersistentIterator My::SessionIterator My::Chat))
# specify path to My/Examples.pm here
-> dispatch_to('/Your/Path/To/Deployed/Modules', 'Module::Name', 'Module::method')
;
# you don't need to use next line if you specified your password in new()
$server->login('user' => 'password') or die "Can't authenticate to SMTP server\n";
# handle will return number of processed mails
# you can organize loop if you want
$server->handle while sleep 10;
DESCRIPTION
===========
COPYRIGHT
=========
Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
AUTHOR
======
Paul Kulchenko (paulclinger@yahoo.com)
File: pm.info, Node: SOAP/Transport/TCP, Next: SOAP/TypeMapper, Prev: SOAP/Transport/POP3, Up: Module List
Server/Client side TCP support for SOAP::Lite
*********************************************
NAME
====
SOAP::Transport::TCP - Server/Client side TCP support for SOAP::Lite
SYNOPSIS
========
use SOAP::Transport::TCP;
my $daemon = SOAP::Transport::TCP::Server
-> new (LocalAddr => 'localhost', LocalPort => 82, Listen => 5, Reuse => 1)
-> objects_by_reference(qw(My::PersistentIterator My::SessionIterator My::Chat))
-> dispatch_to('/Your/Path/To/Deployed/Modules', 'Module::Name', 'Module::method')
;
print "Contact to SOAP server at ", join(':', $daemon->sockhost, $daemon->sockport), "\n";
$daemon->handle;
DESCRIPTION
===========
COPYRIGHT
=========
Copyright (C) 2000-2001 Paul Kulchenko. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
AUTHOR
======
Paul Kulchenko (paulclinger@yahoo.com)
File: pm.info, Node: SOAP/TypeMapper, Next: SOAP/TypedPrimitive, Prev: SOAP/Transport/TCP, Up: Module List
Maps Perl types to their serializer/deserializer classes
********************************************************
NAME
====
SOAP::TypeMapper - Maps Perl types to their serializer/deserializer
classes
SYNOPSIS
========
This is an extensibility point built in to SOAP/Perl to allow for
future expansion, especially with regards to the eventual development of
an XML Schema-based metadata format. In the short term, you can use this
extensibility point to add support for marshaling blessed object
references.
This is currently an experimental feature and will be documented in
more detail once we have a bit more implementation experience. Feel free
to peruse the sources and use this class if you like, and send feedback.
DESCRIPTION
===========
Forthcoming...
AUTHOR
======
Keith Brown
File: pm.info, Node: SOAP/TypedPrimitive, Next: SOAP/TypedPrimitiveSerializer, Prev: SOAP/TypeMapper, Up: Module List
Wrapper for xsd primitives that need explicit SOAP type attributes
******************************************************************
NAME
====
SOAP::TypedPrimitive - Wrapper for xsd primitives that need explicit
SOAP type attributes
SYNOPSIS
========
use SOAP::TypedPrimitive;
my $body = { a => SOAP::TypedPrimitive->new(3, 'float'), b =>
SOAP::TypedPrimitive->new(4, 'float'), };
DESCRIPTION
===========
In some cases it is desirable to provide explicit types for parameters
being passed to SOAP methods. One legitimate case is when you need to
disambiguate a call to a method that is one of many with the same name
that only differ by the parameter types (i.e., an 'overloaded' method).
new(value, typeString)
----------------------
Returns a blessed object reference that has a custom serializer that
will emit explicit xsi:type attributes. For instance, the above example
produces the following SOAP representation for 'a':
3
Note that this class only supports primitive types defined in the xsd
namespace (see XML Schema Part 2: Datatypes)
DEPENDENCIES
============
SOAP::Defs SOAP::TypedPrimitiveSerializer
AUTHOR
======
Keith Brown
SEE ALSO
========
SOAP::EnvelopeMaker
File: pm.info, Node: SOAP/TypedPrimitiveSerializer, Next: SOM, Prev: SOAP/TypedPrimitive, Up: Module List
serializer for xsd scalars
**************************
NAME
====
SOAP::TypedPrimitiveSerializer - serializer for xsd scalars
DEPENDENCIES
============
SOAP::TypedPrimitive
AUTHOR
======
Keith Brown
SEE ALSO
========
SOAP::TypedPrimitive
File: pm.info, Node: SOM, Next: SPOPS, Prev: SOAP/TypedPrimitiveSerializer, Up: Module List
Perl extension for access to SOM and DSOM objects.
**************************************************
NAME
====
SOM - Perl extension for access to SOM and DSOM objects.
SYNOPSIS
========
use SOM;
blah blah blah
DESCRIPTION
===========
Supported types
---------------
(exported with the tag `:types'):
tk_short
tk_ushort
tk_long
tk_ulong
tk_float
tk_double
tk_char
tk_boolean
tk_octet
tk_enum
tk_string
tk_pointer # Not yet?
tk_void # Output only
Supported services
------------------
$class = Find_Class($classname, $major, $minor)
Returns SOM Class object. Use `$major = $minor = 0' if you do not need
a version check.
$obj = $class->NewObject()
Creates a new instance of an object of the given class.
$repo = RepositoryNew()
Returns an object for access to Repository.
SOMClass()
Returns the SOM (meta)class `SOMClass'.
SOMObject()
Returns the SOM class `SOMObject'.
SOMClassMgr()
Returns the SOM class `SOMClassMgr'.
SOMClassMgrObject()
Returns the standard `SOMClassMgrObject' object.
$obj->Dispatch0($method_name)
Dispatches a method with void return and no arguments (not supported,
fatal error if $method_name cannot be resolved).
$obj->Dispatch_templ($method_name, $template, ...)
Dispatches a method with return type and arguments described by a
$template. See `t/animal.t' how to build a template.
$obj->GetClass()
Return the class of the object (as a SOM object).
Primitive classes
=================
Some SOM methods are hardwired into the module, they operate on Perl
objects with names ending on `Ptr'. (Other SOM methods are currently
supported with Dispatch_templ() method only.)
Note that support of Repository classes is much more complete than for
other classes, since support on auto-import of methods is impossible
without this.
DSOM-related primitive classes are listed in `Working with DSOM' in
this node.
SOMObjectPtr
------------
`GetClass'
Returns the class object.
`GetClassName'
Returns the class name.
Additionally, two non-SOM methods are made available: Dispatch0() and
Dispatch_templ().
SOMClassPtr
-----------
`NewObject'
Returns a new object of the given class.
ContainedPtr
------------
All the methods take environment as an argument:
$name = $obj->name($env)
name
String name of the element (unique inside the immediate parent).
id
String id of the element (unique in the repository).
`defined_in'
String id of the immediate parent.
`within'
Returns a list of containers with definitions of this object.
describe
Returns information defined in the IDL specification of this object.
*Memory management for this???*. Return type is
AttributeDescriptionPtr.
ContainerPtr
------------
`lookup_name'
Returns a list of objects with the given name within a specified
Container object, or within objects contained in the Container object.
$obj->lookup_name($env, $name, $levels, $type, $noinherited)
$levels should be -1 to search all the kids-containers as well,
otherwise should be 1. $type should be one of
AttributeDef ConstantDef ExceptionDef InterfaceDef
ModuleDef ParameterDef OperationDef TypeDef all
If $noinherited, any inherited objects will not be returned.
`contents'
Returns the list of contained elements.
$obj->contents($env, $type, $noinherited)
Parameters have the same sense as for the `lookup_name' method.
AttributeDescriptionPtr
-----------------------
*Should be scraped: AttributeDescriptionPtr should be substituted by
proper subclass of Contained!*
The methods do not take environment as an argument:
$typecode = $attr->type()
In addition to methods name(), id(), defined_in() similar to ones in
`Contained', has two additional methods:
type
`TypeCodePtr' object which describes the type of the attribute.
readonly
whether the attribute is readonly.
Currently there is no value() method.
OperationPtr
------------
All the methods take environment as an argument:
$name = $op->result($env)
result
TypeCode of the return value.
ParameterPtr
------------
All the methods take environment as an argument:
$name = $argN->type($env)
type
TypeCode of this argument.
mode
One of the strings `INOUT', `OUT', IN.
TypeCode
--------
All the methods take environment as an argument:
$kind = $tc->kind($env)
`kind'
Returns the type of the TypeCode. Types are the same as `Supported
types' in this node.
`param_count'
Returns the number of parameters encoded in the TypeCode.
parameter
Returns the nth parameter encoded in the TypeCode as any. n changes
from 0 to *param_count*` - 1'.
$p = $tc->parameter($env, 2);
any
---
All the methods take environment as an argument:
$type = $any->type($env)
type
Returns the TypeCode of the value stored in the any.
value
Returns the value stored in the any. Only elementary types are
supported now.
Repository
==========
Since Container/`Contained' are completely supported by primitive
classes, one can walk the Repository tree any way one is pleased. We use
only the following subtree of the Repository: inside toplevel we find
`InterfaceDef' elements (which carry information about SOM classes),
inside an `InterfaceDef' we look for `OperationDef' elements (which
correspond to methods in the class), and inside an `OperationDef' we look
for `ParameterDef' elements (which correspond to arguments of a method).
BUGS
----
We consider `ContainedContainerPtr' as being both a ContainerPtr and
ContainedPtr. But not all of them are. This is bad, since calling C SOM
bindings on an object of unappropriate type is not catchable.
Working with DSOM
=================
After any call which includes $ev, one should `$ev-'Clear> to avoid
memory leaks. Before this call $ev can be expected for error info.
Package SOM contains following *major codes* of exceptions:
SYSTEM_EXCEPTION, USER_EXCEPTION, NO_EXCEPTION (exportable with tag
`:environment').
This API is very experimental. Read DSOM reference to know what these
calls are doing.
Starting/stopping servers
-------------------------
DSOM to WPS requires two servers: one is a SOMD server (a separate
process), another is WPSD server (extra thread(s) in WPS shell process).
To check existence: SOM::IsSOMDDReady(), SOM::IsWPDServerReady().
To create: `SOM::RestartSOMDD(1)', `SOM::RestartWPDServer(1)'.
To stop: `SOM::RestartSOMDD(0)', `SOM::RestartWPDServer(0)'.
Keep in mind that servers are not refcounted, so it maybe not a very
good idea to shut them down even if did not run when you started (since
somebody else could have started to use them in between).
Additionally, stopping servers when they did not completely started
could lead to problems.
A convenience function `SOM::Ensure_Servers($shutdown_dsom,
$shutdown_wpsd)' is provided. If the arguments are given, servers will be
shutdown at end of run if they were not running when this function was
called. (Exportable with `:dsom')
Class `EnvironmentPtr'
----------------------
To create:
$ev = SOM::CreateLocalEnvironment();
(exportable with tag `:environment').
Methods:
$major = $ev->major;
$stringID = $ev->id;
$minor = $ev->id; # 0 if $ev->major != SYSTEM_EXCEPTION
$state = $ev->completed; # undef if $ev->major != SYSTEM_EXCEPTION
# or state is not YES or NO, otherwise 0 or 1
$ev->Clear; # Free() data if $ev->major == SYSTEM_EXCEPTION
A simpleminded error reporter is made available as method Check:
$err = $ev->Check and warn "Got exception $err";
$err is formatted as `MAJOR=2 ID='OPSYS' MINOR=343 COMPLETED=NO'.
Package `SOM::SOMDeamon'
------------------------
Functions:
Init($ev);
Uninit($ev);
ClassMgrObject(); # Default SOMD class manager
ObjectMgr(); # Default SOMD object manager
WPClassManagerNew(); # One can Merge the result with ObjectMgr()
Class `SOMClassManagerPtr'
--------------------------
Methods:
$oldmgr->MergeInto($newmgr);
Class `ObjectMgrPtr'
--------------------
Methods:
$mgr->ReleaseObject($ev, $servername);
Class `SOMDObjectMgrPtr'
------------------------
ISA `ObjectMgrPtr'.
Methods:
$server = $mgr->FindServerByName($ev, $servername);
Class `SOMDServerPtr'
---------------------
Methods:
$server->GetClassObj($ev, $classname);
Example
-------
Initialize:
use SOM ':class', ':dsom', ':environment';
Ensure_Servers();
$ev = SOM::CreateLocalEnvironment();
sub EnvironmentPtr::CheckAndWarn {
my $err; $err = $ev->Check and warn "Got exception $err";
}
Start class dispatchers:
SOM::SOMDeamon::Init($ev);
$ev->CheckAndWarn;
$SOM_ClassMgr = SOM::SOMDeamon::ClassMgrObject or die;
$WPS_ClassMgr = SOM::SOMDeamon::WPClassManagerNew or die;
$SOM_ClassMgr->MergeInto($WPS_ClassMgr); # In fact MergeFrom
Init_WP_Classes(); # Otherwise cannot GetClassObj('WPFolder')
$server = SOM::SOMDeamon::ObjectMgr->FindServerByName($ev, "wpdServer")
or die;
$ev->CheckAndWarn;
Get a class object of requested type:
$classFolder = $server->GetClassObj($ev, "WPFolder") or die;
$ev->CheckAndWarn;
## ... Do some work with $folderClass
Shut down dispatchers:
SOM::SOMDeamon::ObjectMgr->ReleaseObject($ev, $server);
$ev->CheckAndWarn;
SOM::SOMDeamon::Uninit($ev);
$ev->CheckAndWarn;
EXPORT
======
None by default. Tags `:types', `:class'.
AUTHOR
======
A. U. Thor, a.u.thor@a.galaxy.far.far.away
BUGS
====
Only primitive types of parameters and return value are supported.
Only in-parameters are supported.
No memory management is done at all.
Exception is not analysed.
SOM Objects have type SOMObjectPtr, SOM Classes have type SOMClassPtr
etc.
Methods may be dispatched only when a signature is explicitely
described.
SEE ALSO
========
perl(1).
File: pm.info, Node: SPOPS, Next: SPOPS/Configure, Prev: SOM, Up: Module List
Simple Perl Object Persistence with Security
********************************************
NAME
====
SPOPS - Simple Perl Object Persistence with Security
SYNOPSIS
========
# Define an object completely in a configuration file
my $spops = {
myobject => {
class => 'MySPOPS::Object',
isa => qw( SPOPS::DBI ),
...
}, ...
};
# Process the configuration:
SPOPS::Configure->process_config( { config => $spops } );
# Initialize the class
MySPOPS::Object->class_initialize;
# create the object
my $object = MySPOPS::Object->new;
# Set some parameters
$object->{ $param1 } = $value1;
$object->{ $param2 } = $value2;
# Store the object in an inherited persistence mechanism
eval { $object->save };
if ( $@ ) {
my $err_info = SPOPS::Error->get;
die "Error trying to save object:\n",
"$err_info->{user_msg}\n",
"$err_info->{system_msg}\n";
}
OVERVIEW
========
SPOPS - or Simple Perl Object Persistence with Security - allows you to
easily define how an object is composed and save, retrieve or remove it
any time thereafter. It is intended for SQL databases (using the DBI), but
you should be able to adapt it to use any storage mechanism for
accomplishing these tasks. (An early version of this used GDBM, although
it was not pretty.)
The goals of this package are fairly simple:
* 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 (or other domain-specific language) as
possible, but...
* ... do not impose a huge cumbersome framework on the developer
* Make applications easily portable from one database to another
* Allow people to model objects to existing data without modifying the
data
* Include flexibility to allow extensions
* Let people simply issue SQL statements and work with normal datasets
if they want
So this is a class from which you can derive several useful methods.
You can also abstract yourself from a datasource and easily create new
objects.
The subclass is responsible for serializing the individual objects, or
making them persistent via on-disk storage, usually in some sort of
database. See "Object Oriented Perl" by Conway, Chapter 14 for much more
information.
The individual objects or the classes 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.
Tie Interface
-------------
This version of SPOPS supports using a `tie' in this node interface to
get and set the individual data values. You can also use the more
traditional OO get and set operators, but most people will likely find the
hashref interface easier to deal with. (It also means you can interpolate
data into strings: bonus!) Examples are given below.
The tie interface allows the most common operations - fetch data and
put it into a data structure for later use - to be done very easily. It
also hides much of the complexity behind the object for you so that most
of the time you are dealing with a simple hashref.
Serialization
-------------
Since the main SPOPS class from which all SPOPS objects derive has
*Note Storable: Storable, as a parent, you can call any of its methods
from any SPOPS object and have a serialized version of your object. You can
send it over the network, save it for later - whatever you like.
Note that this feature appeared starting version 0.39, so if you have
any issues with it please e-mail the author. There are some issues to be
worked out with configuration and the like, but it basically just works.
What do the objects look like?
------------------------------
Here is an example getting values from CGI.pm and saving an object:
my $q = new CGI;
my $obj = MyUserClass->new();
foreach my $field ( qw( f_name l_name birthdate ) ) {
$obj->{ $field } = $q->param( $field );
}
my $object_id = eval { $obj->save };
if ( $@ ) {
... report error information ...
}
else {
warn " Object saved with ID: $obj->{object_id}\n";
}
You can now retrieve it later using the object_id:
my $obj = MyUserClass->fetch( $object_id );
print "First Name: $obj->{f_name}\n",
"Last Name: $obj->{l_name}\n",
"Birthday: $obj->{birthdate}\n";
You can also associate objects to other objects:
my $primary_group = $user->group;
print "Group Name: $primary_group->{name}\n";
And you can fetch batches of objects at once:
my $user_list = MyUserClass->fetch_group( { where => 'l_name LIKE ?',
value => [ 'w%' ],
order => 'birthdate' } );
foreach my $user ( @{ $user_list } ) {
print " $user->{f_name} $user->{l_name} -- $user->{birthdate}\n";
}
EXAMPLES
========
# Retrieve all themes and print a description
my $themes = eval { $theme_class->fetch_group( { order => 'title' } ) };
if ( $@ ) { ... report error ... }
else {
foreach my $thm ( @{ $themes } ) {
print "Theme: $thm->{title}\n",
"Description: $thm->{description}\n";
}
}
# Create a new user, set some values and save
my $user = $user_class->new;
$user->{email} = 'mymail@user.com';
$user->{first_name} = 'My';
$user->{last_name} = 'User';
my $user_id = eval { $user->save };
if ( $@ ) {
print "There was an error: ", $R->error->report(), "\n";
}
# Retrieve that same user from the database
my $user_id = $cgi->param( 'user_id' );
my $user = eval { $user_class->fetch( $user_id ) };
if ( $@ ) { ... report error ... }
else {
print "The user's first name is: $user->{first_name}\n";
}
my $data = MyClass->new( { field1 => 'value1', field2 => 'value2' } );
# Retrieve values using the hashref
print "The value for field2 is: $data->{field2}\n";
# Set values using the hashref
$data->{field3} = 'value3';
# Save the current data state
eval { $data->save };
if ( $@ ) { ... report error ... }
# Remove the object permanently
eval { $data->remove };
if ( $@ ) { ... report error ... }
# Call arbitrary object methods to get other objects
my $other_obj = eval { $data->call_to_get_other_object() };
if ( $@ ) { ... report error ... }
# Clone the object with an overridden value and save
my $new_data = $data->clone( { field1 => 'new value' } );
eval { $new_data->save };
if ( $@ ) { ... report error ... }
# $new_data is now its own hashref of data --
# explore the fields/values in it
while ( my ( $k, $v ) = each %{ $new_data } ) {
print "$k == $v\n";
}
# Retrieve saved data
my $saved_data = eval { MyClass->fetch( $id ) };
if ( $@ ) { ... report error ... }
else {
while ( my ( $k, $v ) = each %{ $saved_data } ) {
print "Value for $k with ID $id is $v\n";
}
}
# Retrieve lots of objects, display a value and call a
# method on each
my $data_list = eval { MyClass->fetch_group( where => "last_name like 'winter%'" ) };
if ( $@ ) { ... report error ... }
else {
foreach my $obj ( @{ $data_list } ) {
print "Username: $obj->{username}\n";
$obj->increment_login();
}
}
DESCRIPTION
===========
This module is meant to be overridden by a class that will implement
persistence for the SPOPS objects. This persistence can come by way of
flat text files, LDAP directories, GDBM entries, DBI database tables -
whatever. The API should remain the same.
Class Hierarchy
---------------
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
usually just 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 your objects -
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 |
--------------------------
* SPOPS
Abstract base class, provides persistency and security framework
(fetch, save, remove)
Example: You are reading it now!
* SPOPS::MyStorageTechnology
Concrete base class, provides technical implementation of framework
for a particular storage technology (e.g., Filesystem, RDBMS, LDAP,
... )
Example: SPOPS::DBI, SPOPS::GDBM, ...
* SPOPS::MyApplicationClass
User class, provides semantic implementation of framework
(configuration of parent class, e.g., database connection strings,
field mappings, ... )
Example: MyApplication::User, MyApplication::Document, ...
SPOPS Object States
-------------------
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
Around the fetch(), save(), and remove() calls, you can execute helper
functions (pre_fetch(), post_fetch(), pre_save(), post_save(),
pre_remove(), post_remove()), in case you need to prepare anything or
clean up something, according to needs of your storage technology. These
are pushed on a queue based on a search of @ISA, and executed front to end
of the queue. If any of the calls in a given queue returns a false value,
the whole action (save, remove, fetch) is short-circuited (that is, a
failing method bombs out of the action). More information on this is in
`Data Manipulation Callbacks: Rulesets' in this node below.
API
===
The following includes methods within SPOPS and those that need to be
defined by subclasses.
In the discussion below, the following holds:
* When we say *base class*, think *SPOPS*
* When we say *subclass*, think of *SPOPS::DBI* for example
Onward!
Also see the `ERROR HANDLING' in this node section below on how we use
die() to indicate an error and where to get more detailed infromation.
*new( [ \%initialize_data ] )*
Implemented by base class.
This method creates a new SPOPS object. If you pass it key/value pairs
the object will initialize itself with the data (see initialize() for
notes on this).
Note that you can use the key 'id' to substitute for the actual
parameter name specifying an object ID. For instance:
my $uid = $user->id;
if ( eval { $user->remove } ) {
my $new_user = MyUser->new( { id => $uid, fname = 'BillyBob' ... } );
...
}
In this case, we do not need to know the name of the ID field used by
the MyUser class.
Returns on success: a tied hashref object with any passed data already
assigned.
Returns on failure: undef.
Examples:
# Simplest form...
my $data = MyClass->new();
# ...with initialization
my $data = MyClass->new( { balance => 10532,
account => '8917-918234' } );
*clone( \%params )*
Returns a new object from the data of the first. You can override the
original data with that in the \%params passed in.
Examples:
# Create a new user bozo
my $bozo = $user_class->new;
$bozo->{first_name} = 'Bozo';
$bozo->{last_name} = 'the Clown';
$bozo->{login_name} = 'bozosenior';
eval { $bozo->save };
if ( $@ ) { ... report error .... }
# Clone bozo; first_name is 'Bozo' and last_name is 'the Clown',
# as in the $bozo object, but login_name is 'bozojunior'
my $bozo_jr = $bozo->clone( { login_name => 'bozojunior' } );
eval { $bozo_jr->save };
if ( $@ ) { ... report error ... }
initialize()
Implemented by base class, although it is often overridden.
Cycle through the parameters and set any data necessary. This allows
you to construct the object with existing data. Note that the tied hash
implementation ensures that you cannot set infomration as a parameter
unless it is in the field list for your class. For instance, passing the
information:
firt_name => 'Chris'
should likely not set the data, since 'firt_name' is the misspelled
version of the defined field 'first_name'.
*fetch( $oid, [ \%params ] )*
Implemented by subclass.
This method should be called from either a class or another object with
a named parameter of 'id'.
Returns on success: a SPOPS object.
Returns on failure: undef; if the action failed (incorrect fieldname in
the object specification, database not online, database user cannot
select, etc.) a die() will be used to raise an error.
The \%params parameter can contain a number of items - all are optional.
Parameters:
For most SPOPS implementations, you can pass the data source (a DBI
database handle, a GDBM tied hashref, etc.) into the routine.
data
You can use fetch() not just to retrieve data, but also to do the
other checks it normally performs (security, caching, rulesets,
etc.). If you already know the data to use, just pass it in using
this hashref. The other checks will be done but not the actual data
retrieval. (See the C routine in L for an
example.)
skip_security
A true value skips security checks.
skip_cache
A true value skips any use of the cache.
In addition, specific implementations may allow you to pass in other
parameters. (For example, you can pass in 'field_alter' to the *Note
SPOPS/DBI: SPOPS/DBI, implementation so you can format the returned data.)
Example:
my $id = 90192;
my $data = eval { MyClass->fetch( $id ) };
# Read in a data file and retrieve all objects matching IDs
my @object_list = ();
while ( ) {
chomp;
next if ( /\D/ );
my $obj = eval { ObjectClass->fetch( $_ ) };
if ( $@ ) { ... report error ... }
else { push @object_list, $obj if ( $obj ) }
}
*save( [ \%params ] )*
Implemented by subclass.
This method should save the object state in whatever medium the module
works with. Note that the method may need to distinguish whether the
object has been previously saved or not - whether to do an add versus an
update. See the section `TRACKING CHANGES' in this node for how to do
this. The application should not care whether the object is new or
pre-owned.
Returns on success: the ID of the object if applicable, otherwise a
true value;
Returns on failure: undef, and a die() to indicate that the action
failed.
Example:
my $rv = eval { $obj->save };
if ( $@ ) {
warn "Save of ", ref $obj, " did not work properly!";
}
Parameters:
For most SPOPS implementations, you can pass the data source (a DBI
database handle, a GDBM tied hashref, etc.) into the routine.
is_add
A true value forces this to be treated as a new record.
skip_security
A true value skips the security check.
skip_cache
A true value skips any caching.
skip_log
A true value skips the call to 'log_action'
remove()
Implemented by subclass.
Permanently removes the object, or if called from a class removes the
object having an id matching the named parameter of 'id'.
Returns: status code based on success (undef == failure).
Parameters:
For most SPOPS implementations, you can pass the data source (a DBI
database handle, a GDBM tied hashref, etc.) into the routine.
Examples:
# First fetch then remove
my $obj = MyClass->fetch( $id );
my $rv = $obj->remove();
TRACKING CHANGES
================
The object tracks whether any changes have been made since it was
instantiated and keeps an internal toggle switch. You can query the toggle
or set it manually.
$obj->changed();
Returns 1 if there has been change, undef if not.
$obj->has_change();
Sets the toggle to true.
$obj->clear_change();
Sets the toggle to false.
Example:
if ( $obj->changed() ) {
my $rv = $obj->save();
}
Note that this can (and should) be implemented within the subclass, so
you as a user can simply call:
$obj->save();
And not worry about whether it has been changed or not. If there has
been any modification, the system will save it, otherwise it will not.
*Automatically Created Accessors*
In addition to getting the data for an object through the hashref
method, you can also get to the data with accessors named after the fields.
For example, given the fields:
$user->{f_name}
$user->{l_name}
$user->{birthday}
You can call to retrieve the data:
$user->f_name();
$user->l_name();
$user->birthday();
Note that this is only to read the data, not to change it. The system
does this using AUTOLOAD, and after the first call it automatically
creates a subroutine in the namespace of your class which handles future
calls so there is no need for AUTOLOAD on the second or future calls.
DATA ACCESS METHODS
===================
Most of this information can be accessed through the CONFIG hashref,
but we also need to create some hooks for subclasses to override if they
wish. For instance, language-specific objects may need to be able to
modify information based on the language abbreviation.
We have simple methods here just returning the basic CONFIG
information. The following are defined:
* lang ( $ )
Returns a language code (e.g., 'de' for German; 'en' for English).
This only works if defined by your class.
* no_cache ( bool )
Returns a boolean based on whether this object can be cached or not.
This does not mean that it *will* be cached, just whether the class
allows its objects to be cached.
* field( \% )
Returns a hashref (which you can sort by the values if you wish) of
fieldnames used by this class.
* field_list( \@ )
Returns an arrayref of fieldnames used by this class.
* timestamp_field ( $ )
Returns a fieldname used for the timestamp. Having a blank or
undefined value for this is ok. But if you do define it, your UPDATEs
will be checked to ensure that the timestamp values match up. If not,
the system will throw an error. (Note, this is not yet implemented.)
Subclasses can define their own where appropriate.
"GLOBALS"
=========
These objects are tied together by just a few things:
*global_config*
A few items sprinkled throughout the SPOPS hierarchy need information
provided in a configuration file. See *Note SPOPS/Configure:
SPOPS/Configure, for more information about what should be in it, what
form it should take and some of the nifty tricks you can do with it.
Returns: a hashref of configuration information.
*global_cache*
A caching object. If you have
{cache}->{SPOPS}->{use}
in your configuration set to '0', then you do not need to worry about
this. Otherwise, the caching module should implement:
The method get(), which returns the property values for a particular
object.
$cache->get( { class => 'SPOPS-class', id => 'id' } )
The method set(), which saves the property values for an object into
the cache.
$cache->set( { data => $spops_object } );
This is a fairly simple interface which leaves implementation pretty
much wide open.
Note that subclasses may also have items that must be accessible to all
children - see *Note SPOPS/DBI: SPOPS/DBI, and the `global_db_handle'
method.
DATA MANIPULATION CALLBACKS: RULESETS
=====================================
When a SPOPS object calls fetch/save/remove, the base class takes care
of most of the details for retrieving and constructing the object.
However, sometimes you want to do something more complex or different.
Each data manipulation method allows you to define two methods to
accomplish these things. One is called before the action is taken (usually
at the very beginning of the action) and the other after the action has
been successfully completed.
What kind of actions might you want to accomplish? Cascading deletes
(when you delete one object, delete a number of other dependent objects as
well); dependent fetches (when you fetch one object, fetch all its
component objects as well); implement a consistent data layer (such as
full-text searching) by sending all inserts and updates to a separate
module or daemon. Whatever.
Each of these actions is a rule, and together they are rulesets. There
are some fairly simple guidelines to rules:
1. Each rule is independent of every other rule. Why? Rules for a
particular action may be executed in an arbitrary order. You cannot
guarantee that the rule from one class will execute before the rule
from a separate class.
2. A rule should not change the data of the object on which it operates.
Each rule should be operating on the same data. And since guideline 1
states the rules can be executed in any order, changing data for use
in a separate rule would create a dependency between them.
3. If a rule fails, then the action is aborted. This is central to how
the ruleset operates, since it allows inherited behaviors to have a
say on whether a particular object is fetched, saved or removed.
For example, you may want to implement a 'layer' over certain
classes of data. Perhaps you want to collect how many times users from
various groups visit a set of objects on your website. You can create a
fairly simple class that puts a rule into the ruleset of its children that
creates a log entry every time a particular object is fetch()ed. The class
could also contain methods for dealing with this information.
This rule is entirely separate and independent from other rules, and
does not interfere with the normal operation except to add information to
a separate area of the database as the actions are happening. In this
manner, you can think of them as a trigger as implemented in a relational
database. However, triggers can (and often do) modify the data of the row
that is being manipulated, whereas a rule should not.
*pre_fetch_action( { id => $ } )*
Called before a fetch is done, although if an object is retrieved from
the cache this action is skipped. The only argument is the ID of the
object you are trying to fetch.
*post_fetch_action( \% )*
Called after a fetch has been successfully completed, including after a
positive cache hit.
*pre_save_action( { is_add =>; bool } )*
Called before a save has been attempted. If this is an add operation
(versus an update), we pass in a true value for the 'is_add' parameter.
*post_save_action( { is_add => bool } )*
Called after a save has been successfully completed. If this object was
just added to the data store, we pass in a true value for the 'is_add'
parameter.
*pre_remove_action( \% )*
Called before a remove has been attempted.
*post_remove_action( \% )*
Called after a remove has been successfully completed.
FAILED ACTIONS
==============
If an action fails, the 'fail' method associated with that action is
triggered. This can be a notification to an administrator, or saving the
data in the filesystem after a failed save.
*fail_fetch()*
Called after a fetch has been unsuccessful.
*fail_save()*
Called after a save has been unsuccessful.
*fail_remove()*
Called after a remove has been unsuccessful.
CACHING
=======
SPOPS has object caching built-in. As mentioned above, you will need to
define a *global_cache* either in your SPOPS object class one of its
parents. Typically, you will put the *stash class* in the @ISA of your
SPOPS object.
*pre_cache_fetch()*
Called before an item is fetched from the cache; if this is called, we
know that the object is in the cache, we just have not retrieved it yet.
*post_cache_fetch()*
Called after an item is successfully retrieved from the cache.
*pre_cache_save()*
Called before an object has been cached.
*post_cache_save()*
Called after an object has been cached.
*pre_cache_remove()*
Called before an object is removed from the cache.
*post_cache_remove()*
Called after an object is successfully removed from the cache.
OTHER INDIVIDUAL OBJECT METHODS
===============================
*get( $param_name )*
Returns the currently stored information within the object for $param.
my $value = $obj->get( 'username' );
print "Username is $value";
It might be easier to use the hashref interface to the same data, since
you can inline it in a string:
print "Username is $obj->{username}";
You may also use a shortcut of the parameter name as a method call for
the first instance:
my $value = $obj->username();
print "Username is $value";
*set( $param_name, $value )*
Sets the value of $param to $value. If value is empty, $param is set to
undef.
$obj->set( 'username', 'ding-dong' );
Again, you can also use the hashref interface to do the same thing:
$obj->{username} = 'ding-dong';
Note that unlike get, You *cannot* use the shortcut of using the
parameter name as a method. So a call like:
my $username = $obj->username( 'new_username' );
Will silently ignore any parameters that are passed and simply return
the information as get() would.
id()
Returns the ID for this object. Checks in its config variable for the
ID field and looks at the data there. If nothing is currently stored, you
will get nothing back.
Note that we also create a subroutine in the namespace of the calling
class so that future calls take place more quickly.
*changed()*
Retuns the current status of the data in this object, whether it has
been changed or not.
*has_change()*
Sets the *changed* flag of this object to true.
*clear_change()*
Sets the *changed* flag of this object to false.
*is_checking_fields()*
Returns 1 if this object (and class) check to ensure that you use only
the right fieldnames for an object, 0 if not.
*timestamp()*
Returns the value of the timestamp_field for this object, undef if the
timestamp_field is not defined.
*timestamp_compare( $ts_check )*
Returns true if $ts_check matches what is in the object, false
otherwise.
*object_description()*
Returns a hashref with three keys of information about a particular
object:
url
URL that will display this object
name
Name of this general class of object (e.g., 'News')
title
Title of this particular object (e.g., 'Man bites dog, film at 11')
ERROR HANDLING
==============
(See *Note SPOPS/Error: SPOPS/Error, for now - more later!)
NOTES
=====
There is an issue using these modules with Apache::StatINC along with
the startup methodology that calls the *class_initialize* method of each
class when a httpd child is first initialized. If you modify a module
without stopping the webserver, the configuration variable in the class
will not be initialized and you will inevitably get errors.
We might be able to get around this by having most of the configuration
information as static class lexicals. But anything that depends on any
information from the CONFIG variable in request (which is generally passed
into the *class_initialize* call for each SPOPS implementation) will get
hosed.
TO DO
=====
*Allow call to pass information to rulesets*
Modify all calls to `pre_fetch_action' (etc.) to take a hashref of
information that can be used by the ruleset. For instance, if I do not
want an object indexed by the full-text ruleset (even though the class
uses it), I could do:
eval { $obj->save( { full_text_skip => 1 } ) };
*Objects composed of many records*
An idea: Make this data item framework much like the one Brian Jepson
discusses in Web Techniques:
http://www.webtechniques.com/archives/2000/03/jepson/
At least in terms of making each object unique (having an OID). Each
object could then be simply a collection of table name plus ID name in the
object table:
CREATE TABLE objects (
oid int not null,
table_name varchar(30) not null,
id int not null,
primary key( oid, table_name, id )
)
Then when you did:
my $oid = 56712;
my $user = User->fetch( $oid );
It would first get the object composition information:
oid table id
=== ===== ==
56712 user 1625
56712 user_prefs 8172
56712 user_history 9102
And create the User object with information from all three tables.
Something to think about, anyway.
BUGS
====
COPYRIGHT
=========
Copyright (c) 2001 intes.net, inc.. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
MORE INFORMATION
================
Find out more about SPOPS - current versions, updates, rants, ideas -
at:
http://www.openinteract.org/SPOPS/
CVS access and mailing lists (currently supported by the
openinteract-dev list) are at:
http://sourceforge.net/projects/openinteract/
AUTHORS
=======
Chris Winters
Christian Lemburg contributed some
documentation and far too many good ideas to implement.
Rusty Foster was also influential in the early
days of this library.
The following people have offered patches to SPOPS:
* Rick Myers