]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/support-scripts/marc_stream_importer.pl
Mid-refactor move data processing into sub
[Evergreen.git] / Open-ILS / src / support-scripts / marc_stream_importer.pl
1 #!/usr/bin/perl
2 # Copyright (C) 2008 Equinox Software, Inc.
3 # Author: Bill Erickson <erickson@esilibrary.com>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 =head1 NAME
16
17 marc_stream_importer.pl - Import MARC records via bare socket connection.
18
19 =head1 SYNOPSIS
20
21 ./marc_stream_importer.pl /openils/conf/opensrf_core.xml \
22     <eg_username> <eg_password> <bib_source> --port <port> --min_servers 2 \
23     --max_servers 20 --log_file /openils/var/log/marc_net_importer.log &
24
25 Note: this script has to be run in the same directory as oils_header.pl
26
27 =head1 DESCRIPTION
28
29 This script is a Net::Server::PreFork instance for shoving records into Evergreen from a remote system.
30
31 =head2 Configuration
32
33 =head3 OCLC Connexion
34
35 To use this script with OCLC Connexion, configure the client as follows:
36
37 Under Tools -> Options -> Export (tab)
38    Create -> Choose Connection -> OK -> Leave translation at "None" 
39        -> Create -> Create -> choose TCP/IP (internet) 
40        -> Enter hostname and Port, leave 'Use Telnet Protocol' checked 
41        -> Create/OK your way out of the dialogs
42    Record Characteristics (button) -> Choose 'UTF-8 Unicode' for the Character Set
43    
44
45 OCLC and Connexion are trademark/service marks of OCLC Online Computer Library Center, Inc.
46
47 =head1 CAVEATS
48
49 WARNING: This script provides no inherent security layer.  Any client that has 
50 access to the server+port can inject MARC records into the system.  
51 Use the available options (like allow/deny) in the Net::Server config file 
52 or via the command line to restrict access as necessary.
53
54 =head1 EXAMPLES
55
56 ./marc_stream_importer.pl /openils/conf/opensrf_core.xml \
57     admin open-ils connexion --port 5555 --min_servers 2 \
58     --max_servers 20 --log_file /openils/var/log/marc_net_importer.log &
59
60 =head1 SEE ALSO
61
62 L<Net::Server::PreFork>, L<marc_stream_importer.conf>
63
64 =head1 AUTHORS
65
66     Bill Erickson <erickson@esilibrary.com>
67     Joe Atzberger <jatzberger@esilibrary.com>
68
69
70 =cut
71
72 use strict; use warnings;
73 use Net::Server::PreFork;
74 use base qw/Net::Server::PreFork/;
75 use MARC::Record;
76 use MARC::Batch;
77 use MARC::File::XML;
78 use MARC::File::USMARC;
79 use File::Basename qw/fileparse/;
80 use Getopt::Long;
81
82 use OpenSRF::Utils::Logger qw/$logger/;
83 use OpenILS::Utils::Cronscript;
84 require 'oils_header.pl';
85 use vars qw/$apputils/;
86
87 # DEFAULTS
88 my $bufsize       = 4096;
89 my $wait_time     = 5;
90 my $bib_source    = 'connexion';
91 my $osrf_config   = '/openils/conf/opensrf_core.xml';
92 my $oils_username = 'admin';
93
94 # DEFAULTS for Net::Server
95 my $filename   = fileparse($0, '.pl');
96 my $conf_file  = (-r "$filename.conf") ? "$filename.conf" : undef;
97 # $conf_file is the Net::Server config for THIS script (not EG), if it exists and is readable
98
99 # $script->session('open-ils.cat') or die "No session created";
100
101 my $oils_password = shift;
102 my $authtoken;
103
104 sub warning {
105     return <<WARNING;
106
107 WARNING:  This script provides no security layer.  Any client that has 
108 access to the server+port can inject MARC records into the system.  
109
110 WARNING
111 }
112
113 print warning();
114 # $0 = 'Evergreen MARC Stream Listener';
115
116 sub xml_import {
117     return $apputils->simplereq(
118         'open-ils.cat', 
119         'open-ils.cat.biblio.record.xml.import',
120         @_
121     );
122 }
123
124 sub process_batch_data {
125     my $data = shift or $logger->error("process_batch_data called without any data");
126     $data or return;
127
128     my $handle;
129     open $handle, '<', \$data; 
130     my $batch = MARC::Batch->new('USMARC', $handle);
131     $batch->strict_off;
132
133     my $index = 0;
134     while(1) {
135
136         my $rec;
137         $index++;
138
139         eval { $rec = $batch->next; };
140
141         if ($@) {
142             $logger->error("Failed parsing MARC record $index");
143             next;
144         }
145
146         last unless $rec;
147
148         my $resp = xml_import($authtoken, $rec->as_xml_record, $bib_source);
149
150         # has the session timed out?
151         if (oils_event_equals($resp, 'NO_SESSION')) {
152             new_auth_token();
153             $resp = xml_import($authtoken, $rec->as_xml_record, $bib_source);   # try again w/ new token
154         }
155         oils_event_die($resp);
156     }
157     return $index;
158 }
159
160 sub process_request {
161     my $self = shift;
162     my $socket = $self->{server}->{client};
163     my $data = '';
164     my $buf;
165
166     # Reading <STDIN> blocks until the client is closed.  Instead of waiting 
167     # for that, give each inbound record $wait_time seconds to fully arrive
168     # and pull the data directly from the socket
169     eval {
170         local $SIG{ALRM} = sub { die "alarm\n" }; 
171         do {
172             alarm $wait_time;
173             last unless $socket->sysread($buf, $bufsize);
174             $data .= $buf;
175         } while(1);
176         alarm 0;
177     };
178     process_batch_data($data);
179 }
180
181
182 # the authtoken will timeout after the configured inactivity period.
183 # When that happens, get a new one.
184 sub new_auth_token {
185     $authtoken = oils_login($oils_username, $oils_password, 'staff') 
186         or die "Unable to login to Evergreen";
187     return $authtoken;
188 }
189
190 osrf_connect($osrf_config);
191 new_auth_token();
192 __PACKAGE__->run();
193