X-Git-Url: http://git.indexdata.com/?p=irspy-moved-to-github.git;a=blobdiff_plain;f=lib%2FZOOM%2FPod.pm;h=9ddbd516295685e00229e190c076a5f63fb91c3d;hp=b70085731a2a0d80cbdf376cd2b5639202e0c83b;hb=e973295d211061e778b542af139d8d9e31c689bb;hpb=d658a9bf604ae2512ca0983b547eea8369ef34a7 diff --git a/lib/ZOOM/Pod.pm b/lib/ZOOM/Pod.pm index b700857..9ddbd51 100644 --- a/lib/ZOOM/Pod.pm +++ b/lib/ZOOM/Pod.pm @@ -1,4 +1,4 @@ -# $Id: Pod.pm,v 1.1 2006-05-05 22:17:02 mike Exp $ +# $Id: Pod.pm,v 1.6 2006-05-10 16:44:57 mike Exp $ package ZOOM::Pod; @@ -7,39 +7,140 @@ use warnings; use ZOOM; +BEGIN { + # Just register the name + ZOOM::Log::mask_str("pod"); + ZOOM::Log::mask_str("pod_unhandled"); +} + +=head1 NAME + +ZOOM::Pod - Perl extension for handling pods of concurrent ZOOM connections + =head1 SYNOPSIS - $conn1 = new ZOOM::Connection("bagel.indexdata.com/gils"); - $conn2 = new ZOOM::Connection("z3950.loc.gov:7090/Voyager"); - $pod = new ZOOM::Pod($conn1, $conn2); - $pod->callback(ZOOM::Event::RECV_SEARCH, \&show_result); - $pod->search_pqf("mineral"); - $pod->wait(); + use ZOOM::Pod; + + $pod = new ZOOM::Pod("bagel.indexdata.com/gils", + "bagel.indexdata.com/marc"); + $pod->callback(ZOOM::Event::RECV_SEARCH, \&completed_search); + $pod->callback(ZOOM::Event::RECV_RECORD, \&got_record); + $pod->search_pqf("the"); + $err = $pod->wait(); + die "$pod->wait() failed with error $err" if $err; + + sub completed_search { + ($conn, undef, $rs) = @_; + print $conn->option("host"), ": found ", $rs->size(), " records\n"; + $rs->records(0, 1, 0); # Queues a request for the record + return 0; + } - sub show_result { - ($conn, $rs, $event) = @_; - print "$conn: found ", $rs->size(), " records\n"; + sub got_record { + ($conn, undef, $rs) = @_; + $rec = $rs->record(0); + print $conn->option("host"), ": got $rec = '", $rec->render(), "'\n"; + return 0; } +=head1 DESCRIPTION + +C provides an API that simplifies asynchronous programming +using ZOOM. A pod is a collection of asynchronous connections that +are run simultaneously to achieve broadcast searching and retrieval. +When a pod is created, a set of connections (or target-strings to +connect to) are specified. Thereafter, they are treated as a unit, +and methods for searching, option-setting, etc. that are invoked on +the pod are delegated to each of its members. + +The key method on a pod is C, which enters a loop accepting +and dispatching events occurring on any of the connections in the pod. +Unless interrupted,the loop runs until there are no more events left, +i.e. no searches are outstanding and no requested records have still +to be received. + +Event dispatching is done by means of callback functions, which can be +registered for each event. A registered callback is invoked whenever +a corresponding event occurs. A special callback can be nominated to +handle errors. + +=head1 METHODS + +=head2 new() + + $pod = new ZOOM::Pod($conn1, $conn2, $conn3); + $pod = new ZOOM::Pod("bagel.indexdata.com/gils", + "bagel.indexdata.com/marc"); + + +Creates a new pod containing one or more connections. Each connection +may be specified either by an existing C object, +which I be asynchronous; or by a ZOOM target string, in which +case the pod module will make the connection object itself. + +Returns the new pod. + =cut sub new { my $class = shift(); my(@conn) = @_; + die "$class with no connections" if @conn == 0; + my @state; # Hashrefs with application state associated with connections foreach my $conn (@conn) { if (!ref $conn) { $conn = new ZOOM::Connection($conn, 0, async => 1); + # The $conn object is always made, even if no there's no + # server. Such errors are caught later, by the _check() + # call in wait(). } + push @state, {}; } return bless { conn => \@conn, + state => \@state, rs => [], callback => {}, }, $class; } +=head2 option() + + $oldElemSet = $pod->option("elementSetName"); + $pod->option(elementSetName => "b"); + +Sets a specified option in all the connections in a pod. Returns the +old value that the option had in first of the connections in the pod: +be aware that this value was not necessarily shared by all the members +of the pod ... but that is true often enough to be useful. + +=cut + +sub option { + my $this = shift(); + my($key, $value) = @_; + + my $old = $this->{conn}->[0]->option($key); + foreach my $conn (@{ $this->{conn} }) { + $conn->option($key, $value); + } + + return $old; +} + +=head2 callback() + +I<###> + +It is passed the connection that the event happened on, a state +hash-reference associated with the connection, the connection's +result-set and the event-type (so that a single function can handle +events of multiple types, switching on the code where necessary). + +=cut + sub callback { my $this = shift(); my($event, $sub) = @_; @@ -51,6 +152,17 @@ sub callback { return $old; } +=head2 search_pqf() + +I<###> + +B +An important simplifying assumption is that each connection can only +have one search active on it at a time - this allows the pod to +maintain a one-to-one mapping between connections and result-sets. + +=cut + sub search_pqf { my $this = shift(); my($pqf) = @_; @@ -60,19 +172,40 @@ sub search_pqf { } } +=head2 wait() + +I<###> + +=cut + sub wait { my $this = shift(); my $res = 0; - print "in wait\n"; while ((my $i = ZOOM::event($this->{conn})) != 0) { my $conn = $this->{conn}->[$i-1]; my $ev = $conn->last_event(); - print("connection ", $i-1, ": ", ZOOM::event_str($ev), "\n"); + my $evstr = ZOOM::event_str($ev); + ZOOM::Log::log("pod", "connection ", $i-1, ": $evstr"); + + eval { + $conn->_check(); + }; if ($@) { + my $sub = $this->{callback}->{exception}; + die $@ if !defined $sub; + $res = &$sub($conn, $this->{state}->[$i-1], + $this->{rs}->[$i-1], $@); + last if $res != 0; + next; + } + my $sub = $this->{callback}->{$ev}; if (defined $sub) { - $res = &$sub($conn, $this->{rs}->[$i-1], $ev); + $res = &$sub($conn, $this->{state}->[$i-1], + $this->{rs}->[$i-1], $ev); last if $res != 0; + } else { + ZOOM::Log::log("pod_unhandled", "unhandled event $ev ($evstr)"); } } @@ -80,4 +213,27 @@ sub wait { } +=head1 SEE ALSO + +The underlying +C +module (part of the +C +distribution). + +=head1 AUTHOR + +Mike Taylor, Emike@indexdata.comE + +=head1 COPYRIGHT AND LICENCE + +Copyright (C) 2006 by Index Data. + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.8.4 or, +at your option, any later version of Perl 5 you may have available. + +=cut + + 1;