1 # ---------------------------------------------------------------
2 # Copyright © 2014 Jason J.A. Stephenson <jason@sigio.com>
4 # This file is part of NCIPServer.
6 # NCIPServer is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # NCIPServer is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with NCIPServer. If not, see <http://www.gnu.org/licenses/>.
18 # ---------------------------------------------------------------
26 # For find_bibliographic_ids:
27 use NCIP::Item::BibliographicItemId;
28 use NCIP::Item::BibliographicRecordId;
32 NCIP::ILS - A base class for NIPServer ILS drivers.
38 $ils = NCIP::ILS->new(name => $config->{NCIP.ils.value});
42 NCIP::ILS is meant as a base class and test implementation of the ILS
43 specific drivers of NCIPServer. If you wish to implement a driver for
44 your specific ILS, then it is recommended you subclass this module and
45 reimplement the methods as necessary.
51 my $class = ref $invocant || $invocant;
52 my $self = bless {@_}, $class;
56 =head1 HANDLER METHODS
58 When NCIPServer receives an incoming message, it translates the
59 requested service into lower case and then checks if the ILS has a
60 method by that name. If it does that method is called with a single
61 argument consisting of the XML request converted to a hash ref via
62 XML::LibXML::Simple. If the ILS does not support that service, then
63 the unsupportedservice method of the ILS is called and the resulting
64 problem response returned to the client.
66 All handler methods must return a NCIP::Response object.
68 The handler methods provided in this base class implementation are
69 those that were required for the initial implemenation of NCIPServer
70 to be used with a particular initiator software. You may add any
71 additional handlers to your implementation as required without needing
72 to alter this base class.
76 # Methods required for SHAREit:
80 Called to handle the AcceptItem service request. The inherited
81 implementation returns the Unsupported Service problem response.
89 return $self->unsupportedservice($request);
92 =head2 cancelrequestitem
94 Called to handle the CancelRequestItem service request. The inherited
95 implementation returns the Unsupported Service problem response.
99 sub cancelrequestitem {
103 return $self->unsupportedservice($request);
108 Called to handle the CheckInItem service request. The inherited
109 implementation returns the Unsupported Service problem response.
117 return $self->unsupportedservice($request);
122 Called to handle the CheckOutItem service request. The inherited
123 implementation returns the Unsupported Service problem response.
131 return $self->unsupportedservice($request);
136 Called to handle the LookupUser service request. The inherited
137 implementation returns the Unsupported Service problem response.
145 return $self->unsupportedservice($request);
150 Called to handle the RenewItem service request. The inherited
151 implementation returns the Unsupported Service problem response.
159 return $self->unsupportedservice($request);
164 Called to handle the RequestItem service request. The inherited
165 implementation returns the Unsupported Service problem response.
173 return $self->unsupportedservice($request);
176 # Other methods, just because.
180 Called to handle the LookupVersion service request. The inherited
181 implementation returns the list of supported versions from
182 NCIP::Const. You probably do not want to reimplement this method in
191 my $response = NCIP::Response->new({type => "LookupVersionResponse"});
193 fromagencyid => $request->{LookupVersion}->{ToAgencyId}->{AgencyId},
194 toagencyid => $request->{LookupVersion}->{FromAgencyId}->{AgencyId},
195 versions => [ NCIP::Const::SUPPORTED_VERSIONS ]
197 $response->data($payload);
202 =head1 USEFUL METHODS
204 These are methods of the base class that you may want to use in your
205 subclass or that are used by NCIPserver or other methods of this base
206 class. You very likely do not want to override these in your
211 =head2 unsupportedservice
213 $response = $ils->unsupportedservice($request);
215 This method has the same signature as a regular service handler
216 method. It returns a response containing an Unsupported Service
217 problem. It is used by NCIP.pm when the ILS cannot handle a message,
218 or your implementation could return this in the case of a
219 service/message you don't actually handle, though you may have the
220 proper function defined.
224 sub unsupportedservice {
228 my $service = $self->parse_request_type($request);
230 my $response = NCIP::Response->new({type => $service . 'Response'});
231 my $problem = NCIP::Problem->new();
232 $problem->ProblemType('Unsupported Service');
233 $problem->ProblemDetail("$service service is not supported by this implementation.");
234 $problem->ProblemElement("NULL");
235 $problem->ProblemValue("Not Supported");
236 $response->problem($problem);
243 $response->header($ils->make_header($request));
245 All subclasses will possibly want to create a ResponseHeader for the
246 response message. Since the code for that could be highly redundant
247 if reimplemented by each subclass, the base class supplies an
248 implementation that retrieves the agency information from the
249 InitiationHeader of the request message, swaps the FromAgencyId with
250 the ToAgencyId, and vice versa. It then returns a NCIP::Header to be
251 used in the NCIP::Response object's header field.
262 my $key = $self->parse_request_type($request);
263 $initheader = $request->{$key}->{InitiationHeader}
264 if ($key && $request->{$key}->{InitiationHeader});
266 if ($initheader && $initheader->{FromAgencyId}
267 && $initheader->{ToAgencyId}) {
268 $header = NCIP::Header->new({
269 FromAgencyId => $initheader->{ToAgencyId},
270 ToAgencyId => $initheader->{FromAgencyId}
277 =head2 parse_request_type
279 $type = $ils->parse_request_type($request);
281 Given the request hashref object, parse_request_type will return the
282 service being requested in the message. This method is called by
283 NCIP.pm in order to determine which handler of the ILS object to call.
284 You may find it convenient to use this method in your own handler
285 implementations. You should not need to override this method in your
290 sub parse_request_type {
295 for my $key (keys %$request) {
296 if (ref $request->{$key} eq 'HASH') {
305 =head2 find_user_barcode
307 $barcode = $ils->find_user_barcode($request);
308 ($barcode, $field) = $ils->find_user_barcode($request);
310 If you have a request type that includes a user barcode identifier
311 value, this routine will find it.
313 It will return the barcode in scalar context, or the barcode and the
314 tag of the field where the barcode was found in list context.
316 If multiple barcode fields are provided, it returns the first one that
317 it finds. This is not necessarily the first one given in the request
318 message. Maybe we should add a plural form of this method to find all
319 of the user barcodes provided?
323 sub find_user_barcode {
329 my $message = $self->parse_request_type($request);
331 # Check for UserId first because it is valid in all messages.
332 my $authinput = $request->{$message}->{UserId};
334 $field = 'UserIdentifierValue';
335 $barcode = $authinput->{$field};
336 } elsif (grep {$_ eq $message} NCIP::Const::AUTHENTICATIONINPUT_MESSAGES) {
337 $field = 'AuthenticationInputData';
338 $authinput = $request->{$message}->{AuthenticationInput};
339 # Convert to array ref if it isn't already.
340 if (ref $authinput ne 'ARRAY') {
341 $authinput = [$authinput];
343 foreach my $input (@$authinput) {
344 if ($input->{AuthenticationInputType} =~ /barcode/i) {
345 $barcode = $input->{$field};
351 # Because XML::LibXML::Simple returns {} for empty text values.
352 undef($barcode) if (ref($barcode) eq 'HASH' && !%{$barcode});
354 return (wantarray) ? ($barcode, $field) : $barcode;
357 =head2 find_item_barcode
359 $barcode = $ils->find_item_barcode($request);
360 ($barcode, $field) = $ils->find_item_barcode($request);
362 If you have a request type that includes an item barcode identifier
363 value, this routine will find it.
365 It will return the barcode in scalar context, or the barcode and the
366 tag of the field where the barcode was found in list context.
368 If multiple barcode fields are provided, it returns the first one that
369 it finds. This is not necessarily the first one given in the request
370 message. Maybe we should add a plural form of this method to find all
371 of the item barcodes provided?
375 sub find_item_barcode {
381 my $message = $self->parse_request_type($request);
383 my $idinput = $request->{$message}->{ItemId};
385 $field = 'ItemIdentifierValue';
386 $idinput = [$idinput] unless (ref($idinput) eq 'ARRAY');
387 foreach my $input (@$idinput) {
388 if ($input->{ItemIdentifierType}) {
389 next unless ($input->{ItemIdentifierType} =~ /barcode/i);
391 $barcode = $input->{ItemIdentifierValue};
392 # Because XML::LibXML::Simple returns {} for empty text values.
393 undef($barcode) if (ref($barcode) eq 'HASH' && !%{$barcode});
398 return (wantarray) ? ($barcode, $field) : $barcode;
401 =head2 find_bibliographic_ids
403 $biblio_ids = $ils->find_bibliographic_ids($request);
404 @biblio_ids = $ils->find_bibliographic_ids($request);
406 Finds the BibliograpicId tags in the request message and returns a
407 list of NCIP::Item::BibliographicItemId or
408 NCIP::Item::BibliographicRecordId depending upon which are found in
409 the request, either or both could be present. If no BibliographicId is
410 found, then it returns an empty list.
412 In array context, it returns an array, in scalar context, an array
417 sub find_bibliographic_ids {
422 # Our return variable, so set this if we find any ids.
425 my $message = $self->parse_request_type($request);
427 # Find the BibliographicId in the xml.
429 if ($request->{$message}->{ItemOptionalFields}->{BibligraphicDescription}) {
430 $idxml = $request->{$message}->{ItemOptionalFields}->{BibligraphicDescription}->{BibliographicId};
431 } elsif ($request->{$message}->{BibliographicDescription}) {
432 $idxml = $request->{$message}->{BibliographicDescription}->{BibliographicId};
434 $idxml = $request->{$message}->{BibliographicId};
437 $idxml = [$idxml] unless (ref($idxml) eq 'ARRAY');
438 foreach my $entry (@$idxml) {
440 if ($entry->{BibliographicRecordId}) {
441 my ($identifier, $agencyid, $code);
442 $identifier = $entry->{BibliographicRecordId}->{BibliographicRecordIdentifier};
443 $code = $entry->{BibliographicRecordId}->{BibliographicRecordIdentifierCode};
444 $agencyid = $entry->{BibliographicRecordId}->{AgencyId};
445 $id = NCIP::Item::BibliographicRecordId->new(
447 BibliographicRecordIdentifier => $identifier,
448 BibliographicRecordIdentifierCode => $code,
449 AgencyId => $agencyid
453 my ($identifier, $code);
454 $identifier = $entry->{BibliographicItemId}->{BibliographicItemIdentifier};
455 $code = $entry->{BibliographicItemId}->{BibliographicItemIdentifierCode};
456 $id = NCIP::Item::BibliographicItemId->new(
458 BibliographicItemIdentifier => $identifier,
459 BibliographicItemIdentifierCode => $code
467 return (wantarray) ? @ids : [@ids];