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 return (wantarray) ? ($barcode, $field) : $barcode;
354 =head2 find_item_barcode
356 $barcode = $ils->find_item_barcode($request);
357 ($barcode, $field) = $ils->find_item_barcode($request);
359 If you have a request type that includes an item barcode identifier
360 value, this routine will find it.
362 It will return the barcode in scalar context, or the barcode and the
363 tag of the field where the barcode was found in list context.
365 If multiple barcode fields are provided, it returns the first one that
366 it finds. This is not necessarily the first one given in the request
367 message. Maybe we should add a plural form of this method to find all
368 of the item barcodes provided?
372 sub find_item_barcode {
378 my $message = $self->parse_request_type($request);
380 my $idinput = $request->{$message}->{ItemId};
382 $field = 'ItemIdentifierValue';
383 $idinput = [$idinput] unless (ref($idinput) eq 'ARRAY');
384 foreach my $input (@$idinput) {
385 if ($input->{ItemIdentifierType}) {
386 next unless ($input->{ItemIdentifierType} =~ /barcode/i);
388 $barcode = $input->{ItemIdentifierValue};
393 return (wantarray) ? ($barcode, $field) : $barcode;
396 =head2 find_bibliographic_ids
398 $biblio_ids = $ils->find_bibliographic_ids($request);
399 @biblio_ids = $ils->find_bibliographic_ids($request);
401 Finds the BibliograpicId tags in the request message and returns a
402 list of NCIP::Item::BibliographicItemId or
403 NCIP::Item::BibliographicRecordId depending upon which are found in
404 the request, either or both could be present. If no BibliographicId is
405 found, then it returns an empty list.
407 In array context, it returns an array, in scalar context, an array
412 sub find_bibliographic_ids {
417 # Our return variable, so set this if we find any ids.
420 my $message = $self->parse_request_type($request);
422 # Find the BibliographicId in the xml.
424 if ($request->{$message}->{ItemOptionalFields}->{BibligraphicDescription}) {
425 $idxml = $request->{$message}->{ItemOptionalFields}->{BibligraphicDescription}->{BibliographicId};
426 } elsif ($request->{$message}->{BibliographicDescription}) {
427 $idxml = $request->{$message}->{BibliographicDescription}->{BibliographicId};
429 $idxml = $request->{$message}->{BibliographicId};
432 $idxml = [$idxml] unless (ref($idxml) eq 'ARRAY');
433 foreach my $entry (@$idxml) {
435 if ($entry->{BibliographicRecordId}) {
436 my ($identifier, $agencyid, $code);
437 $identifier = $entry->{BibliographicRecordId}->{BibliographicRecordIdentifier};
438 $code = $entry->{BibliographicRecordId}->{BibliographicRecordIdentifierCode};
439 $agencyid = $entry->{BibliographicRecordId}->{AgencyId};
440 $id = NCIP::Item::BibliographicRecordId->new(
442 BibliographicRecordIdentifier => $identifier,
443 BibliographicRecordIdentifierCode => $code,
444 AgencyId => $agencyid
448 my ($identifier, $code);
449 $identifier = $entry->{BibliographicItemId}->{BibliographicItemIdentifier};
450 $code = $entry->{BibliographicItemId}->{BibliographicItemIdentifierCode};
451 $id = NCIP::Item::BibliographicItemId->new(
453 BibliographicItemIdentifier => $identifier,
454 BibliographicItemIdentifierCode => $code
462 return (wantarray) ? @ids : [@ids];