Set global handle before calling start_server()
[simpleserver-moved-to-github.git] / SimpleServer.pm
index a295634..e3ee48e 100644 (file)
@@ -1,5 +1,5 @@
 ##
 ##
-##  Copyright (c) 2000-2004, Index Data.
+##  Copyright (c) 2000-2006, 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,
 ##
 ##  Permission to use, copy, modify, distribute, and sell this software and
 ##  its documentation, in whole or in part, for any purpose, is hereby granted,
@@ -25,7 +25,7 @@
 ##
 ##
 
 ##
 ##
 
-## $Id: SimpleServer.pm,v 1.21 2004-06-04 09:57:00 sondberg Exp $
+## $Id: SimpleServer.pm,v 1.33 2007-08-08 12:09:19 mike Exp $
 
 package Net::Z3950::SimpleServer;
 
 
 package Net::Z3950::SimpleServer;
 
@@ -39,7 +39,7 @@ require AutoLoader;
 
 @ISA = qw(Exporter AutoLoader DynaLoader);
 @EXPORT = qw( );
 
 @ISA = qw(Exporter AutoLoader DynaLoader);
 @EXPORT = qw( );
-$VERSION = '0.08';
+$VERSION = '1.06';
 
 bootstrap Net::Z3950::SimpleServer $VERSION;
 
 
 bootstrap Net::Z3950::SimpleServer $VERSION;
 
@@ -69,6 +69,13 @@ sub launch_server {
        my $self = shift;
        my @args = @_;
 
        my $self = shift;
        my @args = @_;
 
+       ### This modal internal interface, in which we set a bunch of
+       #   globals and then call start_server(), is asking for
+       #   trouble.  Instead, we should just pass the $self object
+       #   as a parameter into start_server().
+       if (defined($self->{GHANDLE})) {
+               set_ghandle($self->{GHANDLE});
+       }
        if (defined($self->{INIT})) {
                set_init_handler($self->{INIT});
        }
        if (defined($self->{INIT})) {
                set_init_handler($self->{INIT});
        }
@@ -83,6 +90,12 @@ sub launch_server {
        if (defined($self->{SCAN})) {
                set_scan_handler($self->{SCAN});
        }
        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);
 }
 
        start_server(@args);
 }
@@ -95,6 +108,7 @@ package Net::Z3950::RPN::And;
 package Net::Z3950::RPN::Or;
 package Net::Z3950::RPN::AndNot;
 package Net::Z3950::RPN::Term;
 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;
 
 package Net::Z3950::RPN::Attributes;
 package Net::Z3950::RPN::Attribute;
 
@@ -144,15 +158,14 @@ Net::Z3950::SimpleServer - Simple Perl API for building Z39.50 servers.
        }
   }
 
        }
   }
 
-
   ## Register custom event handlers:
   ## Register custom event handlers:
+  my $z = new Net::Z3950::SimpleServer(GHANDLE = $someObject,
+                                      INIT   =>  \&my_init_handler,
+                                      CLOSE  =>  \&my_close_handler,
+                                      SEARCH =>  \&my_search_handler,
+                                      FETCH  =>  \&my_fetch_handler);
 
 
-  my $z = new Net::Z3950::SimpleServer(                INIT   =>  \&my_init_handler,
-                                               CLOSE  =>  \&my_close_handler,
-                                               SEARCH =>  \&my_search_handler,
-                                               FETCH  =>  \&my_fetch_handler);
   ## Launch server:
   ## Launch server:
-
   $z->launch_server("ztest.pl", @ARGV);
 
 =head1 DESCRIPTION
   $z->launch_server("ztest.pl", @ARGV);
 
 =head1 DESCRIPTION
@@ -208,7 +221,13 @@ means of the SimpleServer object constructor
                        SEARCH  =>      \&my_search_handler,
                        PRESENT =>      \&my_present_handler,
                        SCAN    =>      \&my_scan_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);
+
+In addition, the arguments to the constructor may include GHANDLE, a
+global handle which is made available to each invocation of every
+callback function.  This is typically a reference to either a hash or
+an object.
 
 If you want your SimpleServer to start a thread (threaded mode) to
 handle each incoming Z39.50 request instead of forking a process
 
 If you want your SimpleServer to start a thread (threaded mode) to
 handle each incoming Z39.50 request instead of forking a process
@@ -261,6 +280,7 @@ The argument hash passed to the init handler has the form
                                    ## this member contains user name
             PASS      =>  "yyy"    ## Under same conditions, this member
                                    ## contains the password in clear text
                                    ## this member contains user name
             PASS      =>  "yyy"    ## Under same conditions, this member
                                    ## contains the password in clear text
+            GHANDLE   =>  $obj     ## Global handler specified at creation
             HANDLE    =>  undef    ## Handler of Perl data structure
          };
 
             HANDLE    =>  undef    ## Handler of Perl data structure
          };
 
@@ -290,6 +310,7 @@ mous hash. The structure is the following:
   $args = {
                                    ## Request parameters:
 
   $args = {
                                    ## Request parameters:
 
+            GHANDLE   =>  $obj     ## Global handler specified at creation
             HANDLE    =>  ref,     ## Your session reference.
             SETNAME   =>  "id",    ## ID of the result set
             REPL_SET  =>  0,       ## Replace set if already existing?
             HANDLE    =>  ref,     ## Your session reference.
             SETNAME   =>  "id",    ## ID of the result set
             REPL_SET  =>  0,       ## Replace set if already existing?
@@ -390,10 +411,15 @@ node of one of the above types.
 
 See below for details.
 
 
 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
 =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.)
+all of these subclasses of it.  Not done that yet, but will do one day.)
 
 =back
 
 
 =back
 
@@ -494,6 +520,7 @@ The informations exchanged between client and present handle are:
   $args = {
                                    ## Client/server request:
 
   $args = {
                                    ## Client/server request:
 
+            GHANDLE   =>  $obj     ## Global handler specified at creation
             HANDLE    =>  ref,     ## Reference to datastructure
             SETNAME   =>  "id",    ## Result set ID
             START     =>  xxx,     ## Start position
             HANDLE    =>  ref,     ## Reference to datastructure
             SETNAME   =>  "id",    ## Result set ID
             START     =>  xxx,     ## Start position
@@ -520,11 +547,13 @@ The parameters exchanged between the server and the fetch handler are
   $args = {
                                    ## Client/server request:
 
   $args = {
                                    ## Client/server request:
 
+            GHANDLE   =>  $obj     ## Global handler specified at creation
             HANDLE    =>  ref      ## Reference to data structure
             SETNAME   =>  "id"     ## ID of the requested result set
             OFFSET    =>  nnn      ## Record offset number
             REQ_FORM  =>  "n.m.k.l"## Client requested format OID
             COMP      =>  "xyz"    ## Formatting instructions
             HANDLE    =>  ref      ## Reference to data structure
             SETNAME   =>  "id"     ## ID of the requested result set
             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:
 
 
                                    ## Handler response:
 
@@ -535,6 +564,7 @@ The parameters exchanged between the server and the fetch handler are
             ERR_STR   =>  ""       ## Error string
             SUR_FLAG  =>  0        ## Surrogate diagnostic flag
             REP_FORM  =>  "n.m.k.l"## Provided format OID
             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
          };
 
 The REP_FORM value has by default the REQ_FORM value but can be set to
@@ -566,6 +596,7 @@ an index of a book, you always find something! The parameters exchanged are
   $args = {
                                                ## Client request
 
   $args = {
                                                ## Client request
 
+               GHANDLE         => $obj         ## Global handler specified at creation
                HANDLE          => $ref         ## Reference to data structure
                TERM            => 'start',     ## The start term
                NUMBER          => xx,          ## Number of requested terms
                HANDLE          => $ref         ## Reference to data structure
                TERM            => 'start',     ## The start term
                NUMBER          => xx,          ## Number of requested terms
@@ -610,10 +641,12 @@ between two adjacent entries in the response.
 
 =head2 Close handler
 
 
 =head2 Close handler
 
-The argument hash recieved by the close handler has one element only:
+The argument hash recieved by the close handler has two elements only:
 
   $args = {
                                    ## Server provides:
 
   $args = {
                                    ## Server provides:
+
+            GHANDLE   =>  $obj     ## Global handler specified at creation
             HANDLE    =>  ref      ## Reference to data structure
          };
 
             HANDLE    =>  ref      ## Reference to data structure
          };
 
@@ -621,11 +654,70 @@ What ever data structure the HANDLE value points at goes out of scope
 after this call. If you need to close down a connection to your server
 or something similar, this is the place to do it.
 
 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
 
 =head1 AUTHORS
 
-Anders Sønderberg (sondberg@indexdata.dk) and Sebastian Hammer
-(quinn@indexdata.dk). Substantial contributions made by Mike Taylor
-(mike@miketaylor.org.uk).
+Anders Sønderberg (sondberg@indexdata.dk),
+Sebastian Hammer (quinn@indexdata.dk),
+Mike Taylor (indexdata.com).
 
 =head1 SEE ALSO
 
 
 =head1 SEE ALSO