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 # ---------------------------------------------------------------
29 NCIP::ILS - A base class for NIPServer ILS drivers.
35 $ils = NCIP::ILS->new(name => $config->{NCIP.ils.value});
39 NCIP::ILS is meant as a base class and test implementation of the ILS
40 specific drivers of NCIPServer. If you wish to implement a driver for
41 your specific ILS, then it is recommended you subclass this module and
42 reimplement the methods as necessary.
48 my $class = ref $invocant || $invocant;
49 my $self = bless {@_}, $class;
53 =head1 HANDLER METHODS
55 When NCIPServer receives an incoming message, it translates the
56 requested service into lower case and then checks if the ILS has a
57 method by that name. If it does that method is called with a single
58 argument consisting of the XML request converted to a hash ref via
59 XML::LibXML::Simple. If the ILS does not support that service, then
60 the unsupportedservice method of the ILS is called and the resulting
61 problem response returned to the client.
63 All handler methods must return a NCIP::Response object.
65 The handler methods provided in this base class implementation are
66 those that were required for the initial implemenation of NCIPServer
67 to be used with a particular initiator software. You may add any
68 additional handlers to your implementation as required without needing
69 to alter this base class.
73 # Methods required for SHAREit:
77 Called to handle the AcceptItem service request. The inherited
78 implementation returns the Unsupported Service problem response.
86 return $self->unsupportedservice($request);
89 =head2 cancelrequestitem
91 Called to handle the CancelRequestItem service request. The inherited
92 implementation returns the Unsupported Service problem response.
96 sub cancelrequestitem {
100 return $self->unsupportedservice($request);
105 Called to handle the CheckInItem service request. The inherited
106 implementation returns the Unsupported Service problem response.
114 return $self->unsupportedservice($request);
119 Called to handle the CheckOutItem service request. The inherited
120 implementation returns the Unsupported Service problem response.
128 return $self->unsupportedservice($request);
133 Called to handle the LookupUser service request. The inherited
134 implementation returns the Unsupported Service problem response.
142 return $self->unsupportedservice($request);
147 Called to handle the RenewItem service request. The inherited
148 implementation returns the Unsupported Service problem response.
156 return $self->unsupportedservice($request);
161 Called to handle the RequestItem service request. The inherited
162 implementation returns the Unsupported Service problem response.
170 return $self->unsupportedservice($request);
173 # Other methods, just because.
177 Called to handle the LookupVersion service request. The inherited
178 implementation returns the list of supported versions from
179 NCIP::Const. You probably do not want to reimplement this method in
188 my $response = NCIP::Response->new({type => "LookupVersionResponse"});
190 fromagencyid => $request->{LookupVersion}->{ToAgencyId}->{AgencyId},
191 toagencyid => $request->{LookupVersion}->{FromAgencyId}->{AgencyId},
192 versions => [ NCIP::Const::SUPPORTED_VERSIONS ]
194 $response->data($payload);
199 =head1 USEFUL METHODS
201 These are methods of the base class that you may want to use in your
202 subclass or that are used by NCIPserver or other methods of this base
203 class. You very likely do not want to override these in your
208 =head2 unsupportedservice
210 $response = $ils->unsupportedservice($request);
212 This method has the same signature as a regular service handler
213 method. It returns a response containing an Unsupported Service
214 problem. It is used by NCIP.pm when the ILS cannot handle a message,
215 or your implementation could return this in the case of a
216 service/message you don't actually handle, though you may have the
217 proper function defined.
221 sub unsupportedservice {
225 my $service = $self->parse_request_type($request);
227 my $response = NCIP::Response->new({type => $service . 'Response'});
228 my $problem = NCIP::Problem->new();
229 $problem->ProblemType('Unsupported Service');
230 $problem->ProblemDetail("$service service is not supported by this implementation.");
231 $problem->ProblemElement("NULL");
232 $problem->ProblemValue("Not Supported");
233 $response->problem($problem);
240 $response->header($ils->make_header($request));
242 All subclasses will possibly want to create a ResponseHeader for the
243 response message. Since the code for that could be highly redundant
244 if reimplemented by each subclass, the base class supplies an
245 implementation that retrieves the agency information from the
246 InitiationHeader of the request message, swaps the FromAgencyId with
247 the ToAgencyId, and vice versa. It then returns a NCIP::Header to be
248 used in the NCIP::Response object's header field.
259 my $key = $self->parse_request_type($request);
260 $initheader = $request->{$key}->{InitiationHeader}
261 if ($key && $request->{$key}->{InitiationHeader});
263 if ($initheader && $initheader->{FromAgencyId}
264 && $initheader->{ToAgencyId}) {
265 $header = NCIP::Header->new({
266 FromAgencyId => $initheader->{ToAgencyId},
267 ToAgencyId => $initheader->{FromAgencyId}
274 =head2 parse_request_type
276 $type = $ils->parse_request_type($request);
278 Given the request hashref object, parse_request_type will return the
279 service being requested in the message. This method is called by
280 NCIP.pm in order to determine which handler of the ILS object to call.
281 You may find it convenient to use this method in your own handler
282 implementations. You should not need to override this method in your
287 sub parse_request_type {
292 for my $key (keys %$request) {
293 if (ref $request->{$key} eq 'HASH') {
302 =head2 find_user_barcode
304 $barcode = $ils->find_user_barcode($request);
306 If you have a request type that includes a user barcode identifier
307 value, this routine will find it.
309 It will return the barcode in scalar context, or the barcode and the
310 tag of the field where the barcode was found in list context.
312 If multiple barcode fields are provided, it returns the first one that
313 it finds. This is not necessarily the first one given in the request
314 message. Maybe we should add a plural form of this method to find all
315 of the user barcodes provided?
319 sub find_user_barcode {
325 my $message = $self->parse_request_type($request);
327 # Check for UserId first because it is more common and still valid
329 my $authinput = $request->{$message}->{UserId};
331 $field = 'UserIdentifierValue';
332 if (ref $authinput ne 'ARRAY') {
333 $authinput = [$authinput];
335 foreach my $input (@$authinput) {
336 # UserIdentifierType is optional, so we check if it is
337 # there. If it is, we skip this entry unless the
338 # identifier type contains the string barcode
339 if ($input->{UserIdentifierType}) {
340 next unless ($input->{UserIdentifierType} =~ /barcode/i);
342 # We take the first field we find, unless the
343 # identifier type says it is not a barcode.
344 $barcode = $input->{$field};
347 } elsif ($message eq 'LookupUser') {
348 $field = 'AuthenticationInputData';
349 $authinput = $request->{$message}->{AuthenticationInput};
350 # Convert to array ref if it isn't already.
351 if (ref $authinput ne 'ARRAY') {
352 $authinput = [$authinput];
354 foreach my $input (@$authinput) {
355 if ($input->{AuthenticationInputType} =~ /barcode/i) {
356 $barcode = $input->{$field};
362 return (wantarray) ? ($barcode, $field) : $barcode;
365 =head2 find_item_barcode
367 $barcode = $ils->find_item_barcode($request);
369 If you have a request type that includes an item barcode identifier
370 value, this routine will find it.
372 It will return the barcode in scalar context, or the barcode and the
373 tag of the field where the barcode was found in list context.
375 If multiple barcode fields are provided, it returns the first one that
376 it finds. This is not necessarily the first one given in the request
377 message. Maybe we should add a plural form of this method to find all
378 of the item barcodes provided?
382 sub find_item_barcode {
388 my $message = $self->parse_request_type($request);
390 my $idinput = $request->{$message}->{ItemId};
392 $field = 'ItemIdentifierValue';
393 $idinput = [$idinput] unless (ref($idinput) eq 'ARRAY');
394 foreach my $input (@$idinput) {
395 if ($input->{ItemIdentifierType}) {
396 next unless ($input->{ItemIdentifierType} =~ /barcode/i);
398 $barcode = $input->{ItemIdentifierValue};
403 return (wantarray) ? ($barcode, $field) : $barcode;