]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Search/Biblio.pm
added filtering of big searches and user level exceptions
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Search / Biblio.pm
1 package OpenILS::Application::Search::Biblio;
2 use base qw/OpenSRF::Application/;
3 use strict; use warnings;
4
5 use OpenILS::EX;
6
7 use JSON;
8 use OpenILS::Utils::Fieldmapper;
9 use OpenILS::Utils::ModsParser;
10 use OpenSRF::Utils::SettingsClient;
11
12 use OpenILS::Application::AppUtils;
13
14 use JSON;
15
16 use Time::HiRes qw(time);
17 use OpenSRF::EX qw(:try);
18 use Digest::MD5 qw(md5_hex);
19
20 use XML::LibXML;
21 use XML::LibXSLT;
22
23 my $apputils = "OpenILS::Application::AppUtils";
24
25 # Houses biblio search utilites 
26
27 __PACKAGE__->register_method(
28         method  => "biblio_search_marc",
29         api_name        => "open-ils.search.biblio.marc",
30         argc            => 1, 
31         note            => "Searches biblio information by marc tag",
32 );
33
34 sub biblio_search_marc {
35
36         my( $self, $client, $search_hash, $string ) = @_;
37
38         warn "Building biblio marc session\n";
39         my $session = OpenSRF::AppSession->create("open-ils.storage");
40
41         use Data::Dumper;
42         warn "Sending biblio marc request. String $string\nSearch hash: " . Dumper($search_hash);
43         my $request = $session->request( 
44                         "open-ils.storage.direct.metabib.full_rec.search_fts.index_vector.atomic", 
45                         restrict => $search_hash, 
46                         term            => $string );
47         my $data = $request->gather(1);
48
49         warn Dumper $data;
50
51         $session->finish();
52         $session->disconnect();
53
54         return $data;
55
56 }
57
58
59
60 # ---------------------------------------------------------------------------
61 # takes a list of record id's and turns the docs into friendly 
62 # mods structures. Creates one MODS structure for each doc id.
63 # ---------------------------------------------------------------------------
64 sub _records_to_mods {
65         my @ids = @_;
66         
67         my @results;
68         my @marcxml_objs;
69
70         my $session = OpenSRF::AppSession->create("open-ils.storage");
71         my $request = $session->request(
72                         "open-ils.storage.direct.biblio.record_entry.batch.retrieve",  @ids );
73
74         my $last_content = undef;
75
76         while( my $response = $request->recv() ) {
77
78                 if( $last_content ) {
79                         my $u = OpenILS::Utils::ModsParser->new();
80                         $u->start_mods_batch( $last_content->marc );
81                         my $mods = $u->finish_mods_batch();
82                         $mods->doc_id($last_content->id());
83                         warn "Turning doc " . $mods->doc_id() . " into MODS\n";
84                         $last_content = undef;
85                         push @results, $mods;
86                 }
87
88                 next unless $response;
89
90                 if($response->isa("OpenSRF::EX")) {
91                         throw $response ($response->stringify);
92                 }
93
94                 $last_content = $response->content;
95
96         }
97
98         if( $last_content ) {
99                 my $u = OpenILS::Utils::ModsParser->new();
100                 $u->start_mods_batch( $last_content->marc );
101                 my $mods = $u->finish_mods_batch();
102                 $mods->doc_id($last_content->id());
103                 push @results, $mods;
104         }
105
106         $request->finish();
107         $session->finish();
108         $session->disconnect();
109
110         return \@results;
111
112 }
113
114 __PACKAGE__->register_method(
115         method  => "record_id_to_mods",
116         api_name        => "open-ils.search.biblio.record.mods.retrieve",
117         argc            => 1, 
118         note            => "Provide ID, we provide the mods"
119 );
120
121 # converts a record into a mods object with copy counts attached
122 sub record_id_to_mods {
123
124         my( $self, $client, $org_id, $id ) = @_;
125
126         my $mods_list = _records_to_mods( $id );
127         my $mods_obj = $mods_list->[0];
128         my $cmethod = $self->method_lookup(
129                         "open-ils.search.biblio.record.copy_count");
130         my ($count) = $cmethod->run($org_id, $id);
131         $mods_obj->copy_count($count);
132
133         return $mods_obj;
134 }
135
136
137 __PACKAGE__->register_method(
138         method  => "record_id_to_mods_slim",
139         api_name        => "open-ils.search.biblio.record.mods_slim.retrieve",
140         argc            => 1, 
141         note            => "Provide ID, we provide the mods"
142 );
143
144 # converts a record into a mods object with NO copy counts attached
145 sub record_id_to_mods_slim {
146
147         my( $self, $client, $id ) = @_;
148         warn "Retrieving MODS object for record $id\n";
149         return undef unless(defined $id);
150
151         my $mods_list = _records_to_mods( $id );
152         my $mods_obj = $mods_list->[0];
153         return $mods_obj;
154 }
155
156
157 # Returns the number of copies attached to a record based on org location
158 __PACKAGE__->register_method(
159         method  => "record_id_to_copy_count",
160         api_name        => "open-ils.search.biblio.record.copy_count",
161 );
162
163 __PACKAGE__->register_method(
164         method  => "record_id_to_copy_count",
165         api_name        => "open-ils.search.biblio.metarecord.copy_count",
166 );
167 sub record_id_to_copy_count {
168         my( $self, $client, $org_id, $record_id ) = @_;
169
170         my $method = "open-ils.storage.biblio.record_entry.copy_count.atomic";
171         my $key = "record";
172         if($self->api_name =~ /metarecord/) {
173                 $method = "open-ils.storage.metabib.metarecord.copy_count.atomic";
174                 $key = "metarecord";
175         }
176
177         my $session = OpenSRF::AppSession->create("open-ils.storage");
178         warn "copy_count retrieve $record_id\n";
179         return undef unless(defined $record_id);
180
181         my $request = $session->request(
182                 $method, org_unit => $org_id => $key => $record_id );
183
184
185         my $count = $request->gather(1);
186         $session->disconnect();
187         return [ sort { $a->{depth} <=> $b->{depth} } @$count ];
188
189 }
190
191
192 # used for cat search classes
193 my $cat_search_hash =  {
194
195         author => [ 
196                 { tag => "100", subfield => "a"} ,
197                 { tag => "700", subfield => "a"}, 
198         ],
199
200         title => [ 
201                 { tag => "245", subfield => "a"},
202                 { tag => "242", subfield => "a"}, 
203                 { tag => "240", subfield => "a"},
204                 { tag => "210", subfield => "a"},
205         ],
206
207         subject => [ 
208                 { tag => "650", subfield => "_" }, 
209         ],
210
211         tcn     => [
212                 { tag => "035", subfield => "_" },
213         ],
214
215         isbn    => [
216                 { tag => "020", subfield => "a" },
217         ],
218
219 };
220
221
222 __PACKAGE__->register_method(
223         method  => "biblio_search_tcn",
224         api_name        => "open-ils.search.biblio.tcn",
225         argc            => 3, 
226         note            => "Retrieve a record by TCN",
227 );
228
229 sub biblio_search_tcn {
230
231         my( $self, $client, $tcn ) = @_;
232
233         $tcn =~ s/.*?(\w+)\s*$/$1/o;
234         warn "Searching TCN $tcn\n";
235
236         my $session = OpenSRF::AppSession->create( "open-ils.storage" );
237         my $request = $session->request( 
238                         "open-ils.storage.direct.biblio.record_entry.search.tcn_value", $tcn );
239         my $record_entry = $request->gather(1);
240
241         my @ids;
242         for my $record (@$record_entry) {
243                 push @ids, $record->id;
244         }
245
246         $session->disconnect();
247
248         warn "received ID's for tcn search @ids\n";
249         my $size = @ids;
250
251         return { count => $size, ids => \@ids };
252
253 }
254
255
256 # --------------------------------------------------------------------------------
257 # ISBN
258
259 __PACKAGE__->register_method(
260         method  => "biblio_search_isbn",
261         api_name        => "open-ils.search.biblio.isbn",
262 );
263
264 sub biblio_search_isbn { 
265         my( $self, $client, $isbn ) = @_;
266         throw OpenSRF::EX::InvalidArg 
267
268                 ("biblio_search_isbn needs an ISBN to search")
269                         unless defined $isbn;
270
271         warn "biblio search for ISBN $isbn\n";
272         my $method = $self->method_lookup("open-ils.search.biblio.marc");
273         my ($records) = $method->run( $cat_search_hash->{isbn}, $isbn );
274
275         my $size = @$records;
276         return { count => $size, ids => $records };
277 }
278
279
280
281 # --------------------------------------------------------------------------------
282
283 __PACKAGE__->register_method(
284         method  => "biblio_barcode_to_copy",
285         api_name        => "open-ils.search.asset.copy.find_by_barcode",
286 );
287
288 # turns a barcode into a copy object
289 sub biblio_barcode_to_copy { 
290         my( $self, $client, $barcode ) = @_;
291
292         throw OpenSRF::EX::InvalidArg 
293                 ("search.biblio.barcode needs a barcode to search")
294                         unless defined $barcode;
295
296         warn "copy search for barcode $barcode\n";
297         my $record = OpenILS::Application::AppUtils->simple_scalar_request(
298                         "open-ils.storage", 
299                         "open-ils.storage.direct.asset.copy.search.barcode",
300                         $barcode );
301
302         return undef unless($record);
303         return $record->[0];
304
305 }
306
307 __PACKAGE__->register_method(
308         method  => "biblio_id_to_copy",
309         api_name        => "open-ils.search.asset.copy.batch.retrieve",
310 );
311
312 # turns a barcode into a copy object
313 sub biblio_id_to_copy { 
314         my( $self, $client, $ids ) = @_;
315
316         throw OpenSRF::EX::InvalidArg 
317                 ("search.biblio.batch.retrieve needs a id to search")
318                         unless defined $ids;
319
320         warn "copy search for ids @$ids\n";
321         my $record = OpenILS::Application::AppUtils->simple_scalar_request(
322                         "open-ils.storage", 
323                         "open-ils.storage.direct.asset.copy.batch.retrieve.atomic",
324                         @$ids );
325
326         return $record;
327
328 }
329
330
331 __PACKAGE__->register_method(
332         method  => "fleshed_copy_retrieve",
333         api_name        => "open-ils.search.asset.copy.fleshed.batch.retrieve",
334 );
335
336 # turns a barcode into a copy object
337 sub fleshed_copy_retrieve { 
338         my( $self, $client, $ids ) = @_;
339
340         throw OpenSRF::EX::InvalidArg 
341                 ("search.biblio.batch.retrieve needs a id to search")
342                         unless defined $ids;
343
344         warn "fleshed copy search for id @$ids\n";
345         my $copy = OpenILS::Application::AppUtils->simple_scalar_request(
346                         "open-ils.storage", 
347                         "open-ils.storage.fleshed.asset.copy.batch.retrieve.atomic",
348                         @$ids );
349
350         return $copy;
351 }
352
353
354
355 __PACKAGE__->register_method(
356         method  => "biblio_barcode_to_title",
357         api_name        => "open-ils.search.biblio.find_by_barcode",
358 );
359
360 sub biblio_barcode_to_title {
361         my( $self, $client, $barcode ) = @_;
362
363         if(!$barcode) {
364                 throw OpenSRF::EX::ERROR 
365                         ("Not enough args to find_by_barcode");
366         }
367
368         my $title = $apputils->simple_scalar_request(
369                 "open-ils.storage",
370                 "open-ils.storage.biblio.record_entry.retrieve_by_barcode",
371                 $barcode );
372
373         return { ids => $title->id, count => 1 };
374
375 =head
376         my $u = OpenILS::Utils::ModsParser->new();
377         $u->start_mods_batch( $title->marc );
378         my $mods = $u->finish_mods_batch();
379         $mods->doc_id($title->id());
380         return $mods;
381 =cut
382         
383 }
384
385
386 __PACKAGE__->register_method(
387         method  => "biblio_copy_to_mods",
388         api_name        => "open-ils.search.biblio.copy.mods.retrieve",
389 );
390
391 # takes a copy object and returns it fleshed mods object
392 sub biblio_copy_to_mods {
393         my( $self, $client, $copy ) = @_;
394
395         throw OpenSRF::EX::InvalidArgs 
396                 ("copy.mods.retrieve needs a copy") unless( $copy );
397
398         new Fieldmapper::asset::copy($copy);
399
400         my $volume = OpenILS::Application::AppUtils->simple_scalar_request(
401                 "open-ils.storage",
402                 "open-ils.storage.direct.asset.call_number.retrieve",
403                 $copy->call_number() );
404
405         my $mods = _records_to_mods($volume->record());
406         $mods = shift @$mods;
407         $volume->copies([$copy]);
408         push @{$mods->call_numbers()}, $volume;
409
410         return $mods;
411 }
412
413
414 sub barcode_to_mods {
415
416 }
417
418
419 # --------------------------------------------------------------------------------
420
421
422
423 __PACKAGE__->register_method(
424         method  => "cat_biblio_search_class",
425         api_name        => "open-ils.search.cat.biblio.class",
426 );
427
428
429 sub cat_biblio_search_class {
430
431         my( $self, $client, $org_id, $class, $sort, $string ) = @_;
432
433         throw OpenSRF::EX::InvalidArg 
434                 ("Not enough args to open-ils.search.cat.biblio.class")
435                         unless( defined($org_id) and $class and $sort and $string );
436
437
438         my $search_hash;
439
440         my $method = $self->method_lookup("open-ils.search.biblio.marc");
441         if(!$method) {
442                 throw OpenSRF::EX::PANIC 
443                         ("Can't lookup method 'open-ils.search.biblio.marc'");
444         }
445
446         my ($records) = $method->run( $cat_search_hash->{$class}, $string );
447
448         my @ids;
449         for my $i (@$records) { push @ids, $i->[0]; }
450
451         my $mods_list = _records_to_mods( @ids );
452         return undef unless (ref($mods_list) eq "ARRAY");
453
454         # ---------------------------------------------------------------
455         # append copy count information to the mods objects
456         my $session = OpenSRF::AppSession->create("open-ils.storage");
457
458         my $request = $session->request(
459                 "open-ils.storage.direct.biblio.record_copy_count.batch",  $org_id, @ids );
460
461         for my $id (@ids) {
462
463                 warn "receiving copy counts for doc $id\n";
464
465                 my $response = $request->recv();
466                 next unless $response;
467
468                 if( $response and UNIVERSAL::isa($response, "Error")) {
469                         throw $response ($response->stringify);
470                 }
471
472                 my $count = $response->content;
473                 my $mods_obj = undef;
474                 for my $m (@$mods_list) {
475                         $mods_obj = $m if ($m->doc_id() == $id)
476                 }
477                 if($mods_obj) {
478                         $mods_obj->copy_count($count);
479                 }
480
481                 $client->respond( $mods_obj );
482
483         }       
484         $request->finish();
485
486         $session->finish();
487         $session->disconnect();
488         $session->kill_me();
489         # ---------------------------------------------------------------
490
491         return undef;
492 }
493
494
495
496 __PACKAGE__->register_method(
497         method  => "cat_biblio_search_class_id",
498         api_name        => "open-ils.search.cat.biblio.class.id",
499         argc            => 3, 
500         note            => "Searches biblio information by search class and returns the IDs",
501 );
502
503 sub cat_biblio_search_class_id {
504
505         my( $self, $client, $org_id, $class, $string, $limit, $offset ) = @_;
506
507         $offset ||= 0;
508         $limit  ||= 100;
509         $limit -= 1;
510
511
512         my $bool = ($class eq "subject" || $class eq "keyword");
513         $string = OpenILS::Application::Search->filter_search($string, $bool);
514
515         if(!$string) { 
516                 return OpenILS::EX->new("SEARCH_TOO_LARGE")->ex();
517         }
518
519         warn "Searching cat.biblio.class.id string: $string offset: $offset limit: $limit\n";
520
521         throw OpenSRF::EX::InvalidArg 
522                 ("Not enough args to open-ils.search.cat.biblio.class")
523                         unless( defined($org_id) and $class and $string );
524
525
526         my $search_hash;
527
528         my $cache_key = md5_hex( $org_id . $class . $string );
529         my $id_array = OpenILS::Application::SearchCache->get_cache($cache_key);
530
531         if(ref($id_array)) {
532                 warn "Returning class search from cache\n";
533                 my $size = @$id_array;
534                 my @ids = @$id_array[ $offset..($offset+$limit) ];
535                 return { count => $size, ids => \@ids };
536         }
537
538         my $method = $self->method_lookup("open-ils.search.biblio.marc");
539         if(!$method) {
540                 throw OpenSRF::EX::PANIC 
541                         ("Can't lookup method 'open-ils.search.biblio.marc'");
542         }
543
544         my ($records) = $method->run( $cat_search_hash->{$class}, $string );
545
546         my @cache_ids;
547
548         for my $i (@$records) { 
549                 if(defined($i->[0])) {
550                         push @cache_ids, $i->[0]; 
551                 }
552         }
553
554         my @ids = @cache_ids[ $offset..($offset+$limit) ];
555         my $size = @$records;
556
557         OpenILS::Application::SearchCache->put_cache( 
558                         $cache_key, \@cache_ids, $size );
559
560         return { count =>$size, ids => \@ids };
561
562 }
563
564 __PACKAGE__->register_method(
565         method  => "biblio_search_class_count",
566         api_name        => "open-ils.search.biblio.class.count",
567         argc            => 3, 
568         note            => "Searches biblio information by search class and returns the IDs",
569 );
570 sub biblio_search_class_count {
571
572         my( $self, $client, $class, $string, $org_id, $org_type ) = @_;
573
574         warn "org: $org_id : depth: $org_type\n";
575
576         $org_id         = "1" unless defined($org_id); # xxx
577         $org_type       = 0     unless defined($org_type);
578
579         warn "Searching biblio.class.id\n" . 
580                 "string: $string "              . 
581                 "org_id: $org_id\n"             .
582                 "depth: $org_type\n" ;
583
584         my $bool = ($class eq "subject" || $class eq "keyword");
585         $string = OpenILS::Application::Search->filter_search($string, $bool);
586
587         if(!$string) { 
588                 return OpenILS::EX->new("SEARCH_TOO_LARGE")->ex;
589         }
590
591                 
592         if( !defined($org_id) or !$class or !$string ) {
593                 warn "not enbough args to metarecord search\n";
594                 throw OpenSRF::EX::InvalidArg 
595                         ("Not enough args to open-ils.search.cat.biblio.class")
596         }
597
598         $class =~ s/\s+//g;
599
600         if( ($class ne "title") and ($class ne "author") and 
601                 ($class ne "subject") and ($class ne "keyword") ) {
602                 warn "Invalid search class: $class\n";
603                 throw OpenSRF::EX::InvalidArg ("Not a valid search class: $class")
604         }
605
606         # grab the mr id's from storage
607
608         my $method = "open-ils.storage.metabib.$class.search_fts.metarecord_count";
609         warn "Performing count method $method\n";
610         my $session = OpenSRF::AppSession->create('open-ils.storage');
611
612         my $request = $session->request( $method, 
613                         term => $string, 
614                         org_unit => $org_id, 
615                         depth =>$org_type );
616
617         my $count = $request->gather(1);
618         warn "Received count $count\n";
619
620         return $count;
621 }
622
623
624 __PACKAGE__->register_method(
625         method  => "biblio_search_class",
626         api_name        => "open-ils.search.biblio.class",
627 );
628
629 __PACKAGE__->register_method(
630         method  => "biblio_search_class",
631         api_name        => "open-ils.search.biblio.class.unordered",
632 );
633
634 sub biblio_search_class {
635
636         my( $self, $client, $class, $string, 
637                         $org_id, $org_type, $limit, $offset ) = @_;
638
639         warn "org: $org_id : depth: $org_type : limit: $limit :  offset: $offset\n";
640
641         $offset         ||= 0;
642         $limit          = 100 unless defined($limit and $limit > 0 );
643         $org_id         = "1" unless defined($org_id); # xxx
644         $org_type       = 0     unless defined($org_type);
645
646         warn "Searching biblio.class.id\n" . 
647                 "string: $string "              . 
648                 "\noffset: $offset\n"   .
649                 "limit: $limit\n"                       .
650                 "org_id: $org_id\n"             .
651                 "depth: $org_type\n" ;
652
653         warn "Search filtering string " . time() . "\n";
654         $string = OpenILS::Application::Search->filter_search($string);
655         if(!$string) { return undef; }
656
657         if( !defined($org_id) or !$class or !$string ) {
658                 warn "not enbough args to metarecord search\n";
659                 throw OpenSRF::EX::InvalidArg 
660                         ("Not enough args to open-ils.search.cat.biblio.class")
661         }
662
663         $class =~ s/\s+//g;
664
665         if( ($class ne "title") and ($class ne "author") and 
666                 ($class ne "subject") and ($class ne "keyword") ) {
667                 warn "Invalid search class: $class\n";
668                 throw OpenSRF::EX::InvalidArg ("Not a valid search class: $class")
669         }
670
671         my $method = "open-ils.storage.metabib.$class.search_fts.metarecord.atomic";
672
673         if($self->api_name =~ /order/) {
674                 $method = "open-ils.storage.metabib.$class.search_fts.metarecord.unordered.atomic";
675         }
676
677         warn "MR search method is $method\n";
678
679         my $session = OpenSRF::AppSession->create('open-ils.storage');
680
681         warn "Search making request " . time() . "\n";
682         my $request = $session->request(        
683                 #"open-ils.storage.cachable.metabib.$class.search_fts.metarecord.atomic",
684                 $method,
685                 term            => $string, 
686                 org_unit => $org_id, 
687                 depth           => $org_type, 
688                 limit           => $limit,
689                 offset  => $offset,
690                 );
691
692         my $records = $request->gather(1);
693         warn "Search request complete " . time() . "\n";
694
695         my @all_ids;
696
697         use Data::Dumper;
698         warn "Received " . scalar(@$records) . " id's from class search\n";
699
700         # if we just get one, it won't be wrapped in an array
701         if(!ref($records->[0])) {
702                 $records = [$records]; } 
703         for my $i (@$records) { 
704                 if(defined($i)) {
705                         push @all_ids, $i; 
706                 }
707         }
708
709         my @ids = @all_ids;
710         @ids = grep { defined($_->[0]) } @ids;
711
712         $session->finish();
713         $session->disconnect();
714
715         return { ids => \@ids };
716
717 }
718
719
720
721
722 __PACKAGE__->register_method(
723         method  => "biblio_mrid_to_modsbatch",
724         api_name        => "open-ils.search.biblio.metarecord.mods_slim.retrieve",
725 );
726
727 sub biblio_mrid_to_modsbatch {
728         my( $self, $client, $mrid ) = @_;
729
730         throw OpenSRF::EX::InvalidArg 
731                 ("search.biblio.metarecord_to_mods requires mr id")
732                         unless defined( $mrid );
733
734
735         my $metarecord = OpenILS::Application::AppUtils->simple_scalar_request( "open-ils.storage", 
736                         "open-ils.storage.direct.metabib.metarecord.retrieve", $mrid );
737
738         if(!$metarecord) {
739                 throw OpenSRF::EX::ERROR ("No metarecord exists with the given id: $mrid");
740         }
741
742         my $master_id = $metarecord->master_record();
743
744
745         # check for existing mods
746         if($metarecord->mods()){
747                 warn "We already have mods for " . $metarecord->id . "\n";
748                 my $perl = JSON->JSON2perl($metarecord->mods());
749                 return Fieldmapper::metabib::virtual_record->new($perl);
750         }
751
752
753
754         warn "Creating mods batch for metarecord $mrid\n";
755         my $id_hash = biblio_mrid_to_record_ids( undef, undef,  $mrid );
756         my @ids = @{$id_hash->{ids}};
757
758         if(@ids < 1) { return undef; }
759
760         warn "Master ID is $master_id\n";
761         # grab the master record to start the mods batch 
762
763         my $record = OpenILS::Application::AppUtils->simple_scalar_request( "open-ils.storage", 
764                         "open-ils.storage.direct.biblio.record_entry.retrieve", $master_id );
765
766         if(!$record) {
767                 throw OpenSRF::EX::ERROR 
768                         ("No record returned with id $master_id");
769         }
770
771         my $u = OpenILS::Utils::ModsParser->new();
772         use Data::Dumper;
773         $u->start_mods_batch( $record->marc );
774         my $main_doc_id = $record->id();
775
776         @ids = grep { $_ ne $master_id } @ids;
777
778         # now we have to collect all of the marc objects and push them into a mods batch
779         my $session = OpenSRF::AppSession->create("open-ils.storage");
780         my $request = $session->request(
781                 "open-ils.storage.direct.biblio.record_entry.batch.retrieve",  @ids );
782
783         while( my $response = $request->recv() ) {
784
785                 next unless $response;
786                 if(UNIVERSAL::isa( $response,"OpenSRF::EX")) {
787                         throw $response ($response->stringify);
788                 }
789
790                 my $content = $response->content;
791
792                 if( $content ) {
793                         $u->push_mods_batch( $content->marc );
794                 }
795         }
796
797         my $mods = $u->finish_mods_batch();
798         $mods->doc_id($mrid);
799         $request->finish();
800
801         $client->respond_complete($mods);
802
803         my $mods_string = JSON->perl2JSON($mods->decast);
804
805         $metarecord->mods($mods_string);
806
807         my $req = $session->request( 
808                         "open-ils.storage.direct.metabib.metarecord.update", 
809                         $metarecord );
810
811
812         $req->gather(1);
813
814         $session->finish();
815         $session->disconnect();
816
817         return undef;
818
819 }
820
821
822
823 # converts a mr id into a list of record ids
824
825 __PACKAGE__->register_method(
826         method  => "biblio_mrid_to_record_ids",
827         api_name        => "open-ils.search.biblio.metarecord_to_records",
828 );
829
830 sub biblio_mrid_to_record_ids {
831         my( $self, $client, $mrid ) = @_;
832
833         throw OpenSRF::EX::InvalidArg 
834                 ("search.biblio.metarecord_to_record_ids requires mr id")
835                         unless defined( $mrid );
836
837         warn "Searching for record for MR $mrid\n";
838
839         my $mrmaps = OpenILS::Application::AppUtils->simple_scalar_request( "open-ils.storage", 
840                         "open-ils.storage.direct.metabib.metarecord_source_map.search.metarecord", $mrid );
841
842         my @ids;
843         for my $map (@$mrmaps) { push @ids, $map->source(); }
844
845         warn "Recovered id's [@ids] for mr $mrid\n";
846
847         my $size = @ids;
848
849         return { count => $size, ids => \@ids };
850
851 }
852
853
854
855 __PACKAGE__->register_method(
856         method  => "biblio_record_to_marc_html",
857         api_name        => "open-ils.search.biblio.record.html" );
858
859 my $parser              = XML::LibXML->new();
860 my $xslt                        = XML::LibXSLT->new();
861 my $marc_sheet;
862
863 my $settings_client = OpenSRF::Utils::SettingsClient->new();
864 sub biblio_record_to_marc_html {
865         my( $self, $client, $recordid ) = @_;
866
867         if( !$marc_sheet ) {
868                 my $dir = $settings_client->config_value( "dirs", "xsl" );
869                 my $xsl = $settings_client->config_value(
870                         "apps", "open-ils.search", "app_settings", "marc_html_xsl" );
871
872                 $xsl = $parser->parse_file("$dir/$xsl");
873                 $marc_sheet = $xslt->parse_stylesheet( $xsl );
874         }
875
876
877         my $record = $apputils->simple_scalar_request(
878                 "open-ils.storage", 
879                 "open-ils.storage.direct.biblio.record_entry.retrieve",
880                 $recordid );
881
882         my $xmldoc = $parser->parse_string($record->marc);
883         my $html = $marc_sheet->transform($xmldoc);
884         $html = $html->toString();
885         return $html;
886
887 }
888
889
890
891 __PACKAGE__->register_method(
892         method  => "retrieve_all_copy_locations",
893         api_name        => "open-ils.search.config.copy_location.retrieve.all" );
894
895 my $shelving_locations;
896 sub retrieve_all_copy_locations {
897         my( $self, $client ) = @_;
898         if(!$shelving_locations) {
899                 $shelving_locations = $apputils->simple_scalar_request(
900                         "open-ils.storage", 
901                         "open-ils.storage.direct.asset.copy_location.retrieve.all.atomic");
902         }
903         return $shelving_locations;
904 }
905
906
907
908 __PACKAGE__->register_method(
909         method  => "retrieve_all_copy_statuses",
910         api_name        => "open-ils.search.config.copy_status.retrieve.all" );
911
912 my $copy_statuses;
913 sub retrieve_all_copy_statuses {
914         my( $self, $client ) = @_;
915         if(!$copy_statuses) {
916                 $copy_statuses = $apputils->simple_scalar_request(
917                         "open-ils.storage",
918                         "open-ils.storage.direct.config.copy_status.retrieve.all.atomic" );
919         }
920         return $copy_statuses;
921 }
922
923
924
925
926
927 1;