##
## $Log: SimpleServer.pm,v $
-## Revision 1.6 2001-03-13 14:17:15 sondberg
+## Revision 1.15 2002-09-16 14:00:16 sondberg
+## Updated Changes and added a few lines of documentation.
+##
+## Revision 1.14 2002/03/06 11:30:02 mike
+## Add RPN structure documentation to SimpleServer.pm's POD.
+## Add README to MANIFEST.
+##
+## Revision 1.13 2002/03/06 11:02:04 mike
+## Added simple README file, derived from POD comments in SimpleServer.pm
+## Fixed my (Mike Taylor's) email address
+##
+## Revision 1.12 2002/03/05 20:52:22 sondberg
+## Version 0.05 so that we can release the thing at CPAN.
+##
+## Revision 1.11 2002/03/05 20:49:56 sondberg
+## Added a couple of lines of documentation.
+##
+## Revision 1.10 2002/02/28 11:21:57 mike
+## Add RPN structure to search-handler argument hash.
+##
+## Revision 1.9 2001/08/29 11:48:36 sondberg
+## Added routines
+##
+## Net::Z3950::SimpleServer::ScanSuccess
+## Net::Z3950::SimpleServer::ScanPartial
+##
+## and a bit of documentation.
+##
+## Revision 1.8 2001/08/29 10:29:51 sondberg
+## Added some documentation of scan.
+##
+## Revision 1.7 2001/08/24 14:00:20 sondberg
+## Added support for scan.
+##
+## Revision 1.6 2001/03/13 14:17:15 sondberg
## Added support for GRS-1.
##
@EXPORT = qw(
);
-$VERSION = '0.02';
+$VERSION = '0.06';
bootstrap Net::Z3950::SimpleServer $VERSION;
sub new {
my $class = shift;
- my $args = shift || croak "SimpleServer::new: Usage new(argument hash)";
- my $self = {};
+ my %args = @_;
+ my $self = \%args;
if ($count) {
carp "SimpleServer.pm: WARNING: Multithreaded server unsupported";
}
$count = 1;
- $self->{INIT} = $args->{INIT};
- $self->{SEARCH} = $args->{SEARCH} || croak "SimpleServer.pm: ERROR: Unspecified search handler";
- $self->{FETCH} = $args->{FETCH} || croak "SimpleServer.pm: ERROR: Unspecified fetch handler";
- $self->{CLOSE} = $args->{CLOSE};
- $self->{PRESENT} = $args->{PRESENT};
+ croak "SimpleServer.pm: ERROR: Unspecified search handler" unless defined($self->{SEARCH});
+ croak "SimpleServer.pm: ERROR: Unspecified fetch handler" unless defined($self->{FETCH});
bless $self, $class;
return $self;
if (defined($self->{PRESENT})) {
set_present_handler($self->{PRESENT});
}
+ if (defined($self->{SCAN})) {
+ set_scan_handler($self->{SCAN});
+ }
start_server(@args);
}
+# Register packages that we will use in translated RPNs
+package Net::Z3950::APDU::Query;
+package Net::Z3950::APDU::OID;
+package Net::Z3950::RPN::And;
+package Net::Z3950::RPN::Or;
+package Net::Z3950::RPN::AndNot;
+package Net::Z3950::RPN::Term;
+package Net::Z3950::RPN::Attributes;
+package Net::Z3950::RPN::Attribute;
+
+# Must revert to original package for Autoloader's benefit
+package Net::Z3950::SimpleServer;
+
+
# Autoload methods go after =cut, and are processed by the autosplit program.
1;
my $set_id = $args->{SETNAME};
- my $record = fetch_a_record($args->{OFFSET);
+ my $record = fetch_a_record($args->{OFFSET});
$args->{RECORD} = $record;
if (number_of_hits() == $args->{OFFSET}) { ## Last record in set?
## Register custom event handlers:
- my $handle = Net::Z3950::SimpleServer->new({
- INIT => \&my_init_handler,
+ my $z = new Net::Z3950::SimpleServer( INIT => \&my_init_handler,
CLOSE => \&my_close_handler,
SEARCH => \&my_search_handler,
- FETCH => \&my_fetch_handler
- });
+ FETCH => \&my_fetch_handler);
## Launch server:
- $handle->launch_server("ztest.pl", @ARGV);
+ $z->launch_server("ztest.pl", @ARGV);
=head1 DESCRIPTION
- Search request
- Present request
- Fetching of records
+ - Scan request (browsing)
- Closing down connection
Note that only the Search and Fetch handler functions are required.
The Perl programmer specifies the event handles for the server by
means of the the SimpleServer object constructor
- my $handle = Net::Z3950::SimpleServer->new({
- INIT => \&my_init_handler,
- CLOSE => \&my_close_handler,
- SEARCH => \&my_search_handler,
- PRESENT => \&my_present_handler,
- FETCH => \&my_fetch_handler });
+ my $z = new Net::Z3950::SimpleServer(
+ INIT => \&my_init_handler,
+ CLOSE => \&my_close_handler,
+ SEARCH => \&my_search_handler,
+ PRESENT => \&my_present_handler,
+ SCAN => \&my_scan_handler,
+ FETCH => \&my_fetch_handler);
After the custom event handles are declared, the server is launched
by means of the method
- $handle->launch_server("MyServer.pl", @ARGV);
+ $z->launch_server("MyServer.pl", @ARGV);
Notice, the first argument should be the name of your server
script (for logging purposes), while the rest of the arguments
IMP_NAME => "", ## Z39.50 Implementation name
IMP_VER => "", ## Z39.50 Implementation version
ERR_CODE => 0, ## Error code, cnf. Z39.50 manual
+ USER => "xxx" ## If Z39.50 authentication is used,
+ ## this member contains user name
+ PASS => "yyy" ## Under same conditions, this member
+ ## contains the password in clear text
HANDLE => undef ## Handler of Perl data structure
};
DATABASES => ["xxx"], ## Reference to a list of data-
## bases to search
QUERY => "query", ## The query expression
+ RPN => $obj, ## Reference to a Net::Z3950::APDU::Query
## Response parameters:
try to return good error codes if you run into something you can't or
won't support.
+A more convenient alternative to the QUERY member may be the RPN
+member, which is a reference to a Net::Z3950::APDU::Query object
+representing the RPN query tree. The structure of that object is
+supposed to be self-documenting, but here's a brief summary of what
+you get:
+
+=over 4
+
+=item *
+
+C<Net::Z3950::APDU::Query> is a hash with two fields:
+
+Z<>
+
+=over 4
+
+=item C<attributeSet>
+
+Optional. If present, it is a reference to a
+C<Net::Z3950::APDU::OID>. This is a string of dot-separated integers
+representing the OID of the query's top-level attribute set.
+
+=item C<query>
+
+Mandatory: a refererence to the RPN tree itself.
+
+=back
+
+=item *
+
+Each node of the tree is an object of one of the following types:
+
+Z<>
+
+=over 4
+
+=item C<Net::Z3950::RPN::And>
+
+=item C<Net::Z3950::RPN::Or>
+
+=item C<Net::Z3950::RPN::AndNot>
+
+These three classes are all arrays of two elements, each of which is a
+node of one of the above types.
+
+=item C<Net::Z3950::RPN::Term>
+
+See below for details.
+
+=back
+
+(I guess I should make a superclass C<Net::Z3950::RPN::Node> and make
+all of these subclasses of it. Not done that yet, but will do soon.)
+
+=back
+
+=over 4
+
+=item *
+
+C<Net::Z3950::RPN::Term> is a hash with two fields:
+
+Z<>
+
+=over 4
+
+=item C<term>
+
+A string containing the search term itself.
+
+=item C<attributes>
+
+A reference to a C<Net::Z3950::RPN::Attributes> object.
+
+=back
+
+=item *
+
+C<Net::Z3950::RPN::Attributes> is an array of references to
+C<Net::Z3950::RPN::Attribute> objects. (Note the plural/singular
+distinction.)
+
+=item *
+
+C<Net::Z3950::RPN::Attribute> is a hash with three elements:
+
+Z<>
+
+=over 4
+
+=item C<attributeSet>
+
+Optional. If present, it is dot-separated OID string, as above.
+
+=item C<attributeType>
+
+An integer indicating the type of the attribute - for example, under
+the BIB-1 attribute set, type 1 indicates a ``use'' attribute, type 2
+a ``relation'' attribute, etc.
+
+=item C<attributeValue>
+
+An integer indicating the value of the attribute - for example, under
+BIB-1, if the attribute type is 1, then value 4 indictates a title
+search and 7 indictates an ISBN search; but if the attribute type is
+2, then value 4 indicates a ``greater than or equal'' search, and 102
+indicates a relevance match.
+
+=back
+
+=back
+
+Note that, at the moment, none of these classes have any methods at
+all: the blessing into classes is largely just a documentation thing
+so that, for example, if you do
+
+ { use Data::Dumper; print Dumper($args->{RPN}) }
+
+you get something fairly human-readable. But of course, the type
+distinction between the three different kinds of boolean node is
+important.
+
+By adding your own methods to these classes (building what I call
+``augmented classes''), you can easily build code that walks the tree
+of the incoming RPN. Take a look at C<samples/render-search.pl> for a
+sample implementation of such an augmented classes technique.
+
+
=head2 Present handler
The presence of a present handler in a SimpleServer front-end is optional.
NOTE: The record offset is 1-indexed - 1 is the offset of the first
record in the set.
+=head2 Scan handler
+
+A full featured Z39.50 server should support scan (or in some literature
+browse). The client specifies a starting term of the scan, and the server
+should return an ordered list of specified length consisting of terms
+actually occurring in the data base. Each of these terms should be close
+to or equal to the term originally specified. The quality of scan compared
+to simple search is a guarantee of hits. It is simply like browsing through
+an index of a book, you always find something! The parameters exchanged are
+
+ $args = {
+ ## Client request
+
+ HANDLE => $ref ## Reference to data structure
+ TERM => 'start', ## The start term
+ NUMBER => xx, ## Number of requested terms
+ POS => yy, ## Position of starting point
+ ## within returned list
+ STEP => 0, ## Step size
+
+ ## Server response
+
+ ERR_CODE => 0, ## Error code
+ ERR_STR => '', ## Diagnostic message
+ NUMBER => zz, ## Number of returned terms
+ STATUS => $status, ## ScanSuccess/ScanFailure
+ ENTRIES => $entries ## Referenced list of terms
+ };
+
+where the term list is returned by reference in the scalar $entries, which
+should point at a data structure of this kind,
+
+ my $entries = [
+ { TERM => 'energy',
+ OCCURRENCE => 5 },
+
+ { TERM => 'energy density',
+ OCCURRENCE => 6, },
+
+ { TERM => 'energy flow',
+ OCCURRENCE => 3 },
+
+ ...
+
+ ...
+ ];
+
+The $status flag should be assigned one of two values:
+
+ Net::Z3950::SimpleServer::ScanSuccess On success (default)
+ Net::Z3950::SimpleServer::ScanPartial Less terms returned than requested
+
+The STEP member contains the requested number of entries in the term-list
+between two adjacent entries in the response.
+
=head2 Close handler
The argument hash recieved by the close handler has one element only:
=head1 AUTHORS
Anders Sønderberg (sondberg@indexdata.dk) and Sebastian Hammer
-(quinn@indexdata.dk).
+(quinn@indexdata.dk). Substantial contributions made by Mike Taylor
+(mike@miketaylor.org.uk).
=head1 SEE ALSO
-perl(1).
-
Any Perl module which is useful for accessing the database of your
choice.
=cut
-
-