##
-## Copyright (c) 2000, Index Data.
+## Copyright (c) 2000-2004, Index Data.
##
## Permission to use, copy, modify, distribute, and sell this software and
## its documentation, in whole or in part, for any purpose, is hereby granted,
##
##
-## $Log: SimpleServer.pm,v $
-## 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.
-##
+## $Id: SimpleServer.pm,v 1.28 2006-07-21 22:14:19 mike Exp $
package Net::Z3950::SimpleServer;
require AutoLoader;
@ISA = qw(Exporter AutoLoader DynaLoader);
-# Items to export into callers namespace by default. Note: do not export
-# names by default without a very good reason. Use EXPORT_OK instead.
-# Do not simply export all your public functions/methods/constants.
-@EXPORT = qw(
-
-);
-$VERSION = '0.04';
+@EXPORT = qw( );
+$VERSION = '1.02';
bootstrap Net::Z3950::SimpleServer $VERSION;
if (defined($self->{SCAN})) {
set_scan_handler($self->{SCAN});
}
+ if (defined($self->{SORT})) {
+ set_sort_handler($self->{SORT});
+ }
+ if (defined($self->{EXPLAIN})) {
+ set_explain_handler($self->{EXPLAIN});
+ }
start_server(@args);
}
package Net::Z3950::RPN::Or;
package Net::Z3950::RPN::AndNot;
package Net::Z3950::RPN::Term;
+package Net::Z3950::RPN::RSID;
package Net::Z3950::RPN::Attributes;
package Net::Z3950::RPN::Attribute;
the Perl script to the server. The server calls the registered
subroutines to field incoming requests from Z39.50 clients.
-A reference to an anonymous hash is passed to each handle. Some of
+A reference to an anonymous hash is passed to each handler. Some of
the entries of these hashes are to be considered input and others
output parameters.
-The Perl programmer specifies the event handles for the server by
-means of the the SimpleServer object constructor
+The Perl programmer specifies the event handlers for the server by
+means of the SimpleServer object constructor
my $z = new Net::Z3950::SimpleServer(
INIT => \&my_init_handler,
SEARCH => \&my_search_handler,
PRESENT => \&my_present_handler,
SCAN => \&my_scan_handler,
- FETCH => \&my_fetch_handler);
+ FETCH => \&my_fetch_handler,
+ EXPLAIN => \&my_explain_handler);
+
+If you want your SimpleServer to start a thread (threaded mode) to
+handle each incoming Z39.50 request instead of forking a process
+(forking mode), you need to register the handlers by symbol rather
+than by code reference. Thus, in threaded mode, you will need to
+register your handlers this way:
-After the custom event handles are declared, the server is launched
+ my $z = new Net::Z3950::SimpleServer(
+ INIT => "my_package::my_init_handler",
+ CLOSE => "my_package::my_close_handler",
+ ....
+ .... );
+
+where my_package is the Perl package in which your handler is
+located.
+
+After the custom event handlers are declared, the server is launched
by means of the method
$z->launch_server("MyServer.pl", @ARGV);
are documented in the YAZ toolkit manual: The section on
application invocation: <http://www.indexdata.dk/yaz/yaz-7.php>
+In particular, you need to use the -T switch to start your SimpleServer
+in threaded mode.
+
=head2 Init handler
The init handler is called whenever a Z39.50 client is attempting
$args = {
## Response parameters:
+ IMP_ID => "", ## Z39.50 Implementation ID
IMP_NAME => "", ## Z39.50 Implementation name
IMP_VER => "", ## Z39.50 Implementation version
ERR_CODE => 0, ## Error code, cnf. Z39.50 manual
+ ERR_STR => "", ## Error string (additional info.)
+ 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
};
it is always best to store them in a private session structure -
rather than leaving them in global variables in your script.
-The Implementation name and version are only really used by Z39.50
+The Implementation ID, name and version are only really used by Z39.50
client developers to see what kind of server they're dealing with.
Filling these in is optional.
The ERR_CODE should be left at 0 (the default value) if you wish to
accept the connection. Any other value is interpreted as a failure
-and the client will be shown the door.
+and the client will be shown the door, with the code and the
+associated additional information, ERR_STR returned.
=head2 Search handler
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.
+
+=item C<Net::Z3950::RPN::RSID>
+
+A reference to a result-set ID indicating a previous search. The ID
+of the result-set is in the C<id> element.
+
+=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 one day.)
+
+=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.
OFFSET => nnn ## Record offset number
REQ_FORM => "n.m.k.l"## Client requested format OID
COMP => "xyz" ## Formatting instructions
+ SCHEMA => "abc" ## Requested schema, if any
## Handler response:
ERR_STR => "" ## Error string
SUR_FLAG => 0 ## Surrogate diagnostic flag
REP_FORM => "n.m.k.l"## Provided format OID
+ SCHEMA => "abc" ## Provided schema, if any
};
The REP_FORM value has by default the REQ_FORM value but can be set to
after this call. If you need to close down a connection to your server
or something similar, this is the place to do it.
+=head2 Support for SRU and SRW
+
+Since release 1.0, SimpleServer includes support for serving the SRU
+and SRW protocols as well as Z39.50. These ``web-friendly'' protocols
+enable similar functionality to that of Z39.50, but by means of rich
+URLs in the case of SRU, and a SOAP-based web-service in the case of
+SRW. These protocols are described at
+http://www.loc.gov/sru
+
+In order to serve these protocols from a SimpleServer-based
+application, it is necessary to launch the application with a YAZ
+Generic Frontend Server (GFS) configuration file, which can be
+specified using the command-line argument C<-f> I<filename>. A
+minimal configuration file looks like this:
+
+ <yazgfs>
+ <server>
+ <cql2rpn>pqf.properties</cql2rpn>
+ </server>
+ </yazgfs>
+
+This file specifies only that C<pqf.properties> should be used to
+translate the CQL queries of SRU and SRW into corresponding Z39.50
+Type-1 queries. For more information about YAZ GFS configuration,
+including how to specify an Explain record, see the I<Virtual Hosts>
+section of the YAZ manual at
+http://indexdata.com/yaz/doc/server.vhosts.tkl
+
+The mapping of CQL queries into Z39.50 Type-1 queries is specified by
+a file that indicates which BIB-1 attributes should be generated for
+each CQL index, relation, modifiers, etc. A typical section of this
+file looks like this:
+
+ index.dc.title = 1=4
+ index.dc.subject = 1=21
+ index.dc.creator = 1=1003
+ relation.< = 2=1
+ relation.le = 2=2
+
+This file specifies the BIB-1 access points (type=1) for the Dublin
+Core indexes C<title>, C<subject> and C<creator>, and the BIB-1
+relations (type=2) corresponding to the CQL relations C<E<lt>> and
+C<E<lt>=>. For more information about the format of this file, see
+the I<CQL> section of the YAZ manual at
+http://indexdata.com/yaz/doc/tools.tkl#tools.cql
+
+The YAZ distribution include a sample CQL-to-PQF mapping configuration
+file called C<pqf.properties>; this is sufficient for many
+applications, and a good base to work from for most others.
+
+If a SimpleServer-based application is run without this SRU-specific
+configuration, it can still serve SRU; however, CQL queries will not
+be translated, but passed straight through to the search-handler
+function, as the C<CQL> member of the parameters hash. It is then the
+responsibility of the back-end application to parse and handle the CQL
+query, which is most easily done using Ed Summers' fine C<CQL::Parser>
+module, available from CPAN at
+http://search.cpan.org/~esummers/CQL-Parser/
+
=head1 AUTHORS
-Anders Sønderberg (sondberg@indexdata.dk) and Sebastian Hammer
-(quinn@indexdata.dk).
+Anders Sønderberg (sondberg@indexdata.dk),
+Sebastian Hammer (quinn@indexdata.dk),
+Mike Taylor (indexdata.com).
=head1 SEE ALSO
-perl(1).
-
Any Perl module which is useful for accessing the database of your
choice.
=cut
-
-