Bug 24545: Fix license statements
[koha.git] / Koha / Z3950Responder / ZebraSession.pm
1 #!/usr/bin/perl
2
3 package Koha::Z3950Responder::ZebraSession;
4
5 # Copyright ByWater Solutions 2016
6 #
7 # This file is part of Koha.
8 #
9 # Koha is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # Koha is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with Koha; if not, see <http://www.gnu.org/licenses>.
21
22 use Modern::Perl;
23
24 use base qw( Koha::Z3950Responder::Session );
25
26 use Koha::Logger;
27
28 use ZOOM;
29
30 =head1 NAME
31
32 Koha::Z3950Responder::ZebraSession
33
34 =head1 SYNOPSIS
35
36 Zebra-specific session class that uses C<Koha::Session> as the base class.
37
38 =head1 FUNCTIONS
39
40 =head2 INSTANCE METHODS
41
42 =head3 start_search
43
44     my ($resultset, $hits) = $self->_start_search( $args, $self->{server}->{num_to_prefetch} );
45
46 Connect to Zebra and do the search
47
48 =cut
49
50 sub start_search {
51     my ( $self, $args, $num_to_prefetch, $in_retry ) = @_;
52
53     my $database = $args->{DATABASES}->[0];
54     my ( $connection, $results );
55
56     eval {
57         $connection = C4::Context->Zconn(
58             # We're depending on the caller to have done some validation.
59             $database eq 'biblios' ? 'biblioserver' : 'authorityserver',
60             0 # No, no async, doesn't really help much for single-server searching
61         );
62
63         $results = $connection->search_pqf( $args->{QUERY} );
64
65         $self->log_debug('    retry successful') if ($in_retry);
66     };
67     if ($@) {
68         die $@ if ( ref($@) ne 'ZOOM::Exception' );
69
70         if ( $@->diagset() eq 'ZOOM' && $@->code() == 10004 && !$in_retry ) {
71             $self->log_debug('    upstream server lost connection, retrying');
72             return $self->_start_search( $args, $num_to_prefetch, 1 );
73         }
74
75         $self->_set_error_from_zoom( $args, $@ );
76         $connection = undef;
77     }
78
79     my $hits = $results ? $results->size() : -1;
80     my $resultset = {
81         database => $database,
82         connection => $connection,
83         results => $results,
84         query => $args->{QUERY},
85         hits => $hits
86     };
87
88     return ( $resultset, $hits );
89 }
90
91 =head3 fetch_record
92
93     my $record = $self->_fetch_record( $resultset, $args, $offset, $server->{num_to_prefetch} );
94
95 Fetch a record from Zebra. Caches records in session to avoid too many fetches.
96
97 =cut
98
99 sub fetch_record {
100     my ( $self, $resultset, $args, $index, $num_to_prefetch ) = @_;
101
102     my $record;
103
104     eval {
105         if ( !$resultset->{results}->record_immediate( $index ) ) {
106             my $start = $num_to_prefetch ? int( $index / $num_to_prefetch ) * $num_to_prefetch : $index;
107
108             if ( $start + $num_to_prefetch >= $resultset->{results}->size() ) {
109                 $num_to_prefetch = $resultset->{results}->size() - $start;
110             }
111
112             $self->log_debug("    fetch uncached, fetching $num_to_prefetch records starting at $start");
113
114             $resultset->{results}->records( $start, $num_to_prefetch, 0 );
115         }
116
117         $record = $resultset->{results}->record_immediate( $index )->raw();
118     };
119     if ($@) {
120         die $@ if ( ref($@) ne 'ZOOM::Exception' );
121         $self->_set_error_from_zoom( $args, $@ );
122         return;
123     } else {
124         return $record;
125     }
126 }
127
128 =head3 close_handler
129
130 Callback that is called when a session is terminated
131
132 =cut
133
134 sub close_handler {
135     my ( $self, $args ) = @_;
136
137     foreach my $resultset ( values %{ $self->{resultsets} } ) {
138         $resultset->{results}->destroy();
139     }
140 }
141
142 =head3 _set_error_from_zoom
143
144     $self->_set_error_from_zoom( $args, $@ );
145
146 Log and set error code and diagnostic message from a ZOOM exception
147
148 =cut
149
150 sub _set_error_from_zoom {
151     my ( $self, $args, $exception ) = @_;
152
153     $self->set_error( $args, $self->ERR_TEMPORARY_ERROR, 'Cannot connect to upstream server' );
154     $self->log_error(
155         "Zebra upstream error: " .
156         $exception->message() . " (" .
157         $exception->code() . ") " .
158         ( $exception->addinfo() // '' ) . " " .
159         $exception->diagset()
160     );
161 }
162
163 1;