File Coverage

blib/lib/WebService/ISBNDB/API.pm
Criterion Covered Total %
statement 131 174 75.2
branch 38 84 45.2
condition 7 23 30.4
subroutine 32 40 80.0
pod 22 23 95.6
total 230 344 66.8


line stmt bran cond sub pod time code
1             ###############################################################################
2             #
3             # This file copyright (c) 2006-2008 by Randy J. Ray, all rights reserved
4             #
5             # See "LICENSE" in the documentation for licensing and redistribution terms.
6             #
7             ###############################################################################
8             #
9             # $Id: API.pm 48 2008-04-06 10:38:11Z $
10             #
11             # Description: This is the base class for the API classes: Books,
12             # Publishers, Subjects (and the others as isbndb.com adds
13             # them to the API).
14             #
15             # Functions: _find
16             # _search
17             # add_type
18             # BUILD
19             # class_for_type
20             # copy
21             # find
22             # get_agent
23             # get_api_key
24             # get_default_agent
25             # get_default_agent_args
26             # get_default_api_key
27             # get_default_protocol
28             # get_protocol
29             # get_type
30             # import
31             # new
32             # normalize_args
33             # remove_type
34             # search
35             # set_agent
36             # set_default_agent
37             # set_default_agent_args
38             # set_default_api_key
39             # set_default_protocol
40             # set_protocol
41             # set_type
42             #
43             # Libraries: Class::Std
44             # Error
45             # WebService::ISBNDB::Agent
46             #
47             # Global Consts: $VERSION
48             # COREPROTOS
49             # CORETYPES
50             #
51             ###############################################################################
52              
53             package WebService::ISBNDB::API;
54              
55 10     10   221483 use 5.006;
  10         41  
  10         454  
56 10     10   57 use strict;
  10         20  
  10         370  
57 10     10   95 use warnings;
  10         20  
  10         520  
58 10     10   48 no warnings 'redefine';
  10         22  
  10         426  
59 10     10   51 use vars qw(@ISA $VERSION @TYPES %TYPES);
  10         20  
  10         941  
60 10     10   67 use constant CORETYPES => qw(Authors Books Categories Publishers Subjects);
  10         13  
  10         904  
61              
62 10     10   13013 use Class::Std;
  10         146649  
  10         67  
63 10     10   11318 use Error;
  10         36876  
  10         49  
64             require WebService::ISBNDB::Agent;
65              
66             $VERSION = "0.23";
67              
68             BEGIN
69             {
70 10     10   1433 @ISA = qw(Class::Std);
71              
72 10         40 @TYPES = (CORETYPES);
73 10         22 %TYPES = map { $_ => __PACKAGE__ . "::$_" } @TYPES;
  50         15417  
74             }
75              
76             # Attributes for the ::API class, shared by all the children
77             my %protocol : ATTR(:init_arg :default<>);
78             my %api_key : ATTR(:init_arg :set :default<>);
79             my %type : ATTR(:init_arg :default<>);
80             my %agent : ATTR(:init_arg :default<>);
81             my %agent_args : ATTR(:init_arg :set :default<>);
82              
83             # Default values, for use by {get,set}_default_*
84             my %DEFAULTS = ( protocol => 'REST',
85             api_key => '',
86             agent => undef,
87             agent_args => { agent => __PACKAGE__ . "/$VERSION" } );
88              
89             ###############################################################################
90             #
91             # Sub Name: import
92             #
93             # Description: Importer routine for "use Module" handling.
94             #
95             # Arguments: NAME IN/OUT TYPE DESCRIPTION
96             # $class in scalar Name of class being loaded
97             # %argz in hash Key/value pairs passed in.
98             #
99             # Returns: 1
100             #
101             ###############################################################################
102             sub import
103             {
104 20     20   220 my ($class, %argz) = @_;
105              
106             # Recognized import-keys are "api_key", "protocol", "agent" and
107             # "agent_args":
108 20 50       94 $class->set_default_protocol($argz{protocol}) if $argz{protocol};
109 20 50       65 $class->set_default_api_key($argz{api_key}) if $argz{api_key};
110 20 50       74 $class->set_default_agent($argz{agent}) if $argz{agent};
111 20 50       60 $class->set_default_agent_args($argz{agent_args}) if $argz{agent_args};
112              
113 20         8798 1;
114             }
115              
116             ###############################################################################
117             #
118             # Sub Name: new
119             #
120             # Description: Constructor for the class.
121             #
122             # Arguments: NAME IN/OUT TYPE DESCRIPTION
123             # $class in scalar The class to bless object into
124             # @argz in list Variable list of args, see text
125             #
126             # Globals: %TYPES
127             #
128             # Returns: Success: new object
129             # Failure: Throws Error::Simple
130             #
131             ###############################################################################
132             sub new
133             {
134 19     19   1565 my ($class, @argz) = @_;
135 19         31 my ($type, $self, %obj_defaults, $args, $new);
136              
137             # Need to make sure $class is the name, not a reference, for later tests.
138             # But if it is a reference, we should also save the protocol and api_key
139             # values.
140 19 50       66 if (ref $class)
141             {
142 0         0 $obj_defaults{protocol} = $class->get_protocol;
143 0         0 $obj_defaults{api_key} = $class->get_api_key;
144 0         0 $class = ref($class);
145             }
146              
147             # If $class matches this package, then they are allowed to specify a type
148             # as the leading argument (Books, Publishers, etc.)
149 19 50 66     89 $type = shift(@argz) if (($class eq __PACKAGE__) and (@argz > 1));
150 19   100     88 $args = shift @argz || {};
151              
152 19 50       56 if ($type)
153             {
154 0 0       0 throw Error::Simple("new: Unknown factory type '$type'")
155             unless $type = $class->class_for_type($type);
156             # Make sure it is loaded
157 0         0 eval "require $type;";
158             }
159              
160             # Set any of the defaults if $class came in as an object
161 19 100       106 if (ref $args)
162             {
163 14         72 foreach (qw(protocol api_key))
164             {
165 28 50 33     178 $args->{$_} = $obj_defaults{$_} if ($obj_defaults{$_} and
166             ! $args->{$_});
167             }
168             }
169              
170             # I really hate this part here. I hate having to overload new() just to get
171             # around the only-accepts-hashref-arg thing.
172 19 100       54 if (ref $args)
173             {
174 14 50       113 $new = $type ? $type->new($args) : $class->SUPER::new($args);
175             }
176             else
177             {
178 5 50       37 $new = $type ? $type->new(\%obj_defaults) : $class->new(\%obj_defaults);
179 5         39 $new = $new->find($args);
180             }
181              
182 14         2730 $new;
183             }
184              
185             ###############################################################################
186             #
187             # Sub Name: BUILD
188             #
189             # Description: Builder for this class. See Class::Std.
190             #
191             # Arguments: NAME IN/OUT TYPE DESCRIPTION
192             # $self in ref Object
193             # $id in scalar This object's unique ID
194             # $args in hashref The set of arguments currently
195             # being considered for the
196             # constructor.
197             #
198             # Returns: Success: void
199             # Failure: throws Error::Simple
200             #
201             ###############################################################################
202             sub BUILD
203             {
204 14     14 1 1074 my ($self, $id, $args) = @_;
205              
206 14         68 $self->set_type('API');
207              
208             # If the 'agent' parameter is set, check it's validity. If it is valid, and
209             # 'protocol' is not set, set it from the agent's protocol() method.
210 14 50       45 if ($args->{agent})
211             {
212             # First, test that agent is valid
213 0 0 0     0 throw Error::Simple('Value for "agent" parameter must derive from ' .
214             'WebService::ISBNDB::Agent')
215             unless (ref($args->{agent}) and
216             $args->{agent}->isa('WebService::ISBNDB::Agent'));
217             # Set $args->{protocol} if it isn't already set. Test it if it is.
218 0 0       0 if ($args->{protocol})
219             {
220 0 0       0 throw Error::Simple('Provided agent does not match specified ' .
221             "protocol ('$args->{protocol}')")
222             unless ($args->{agent}->protocol($args->{protocol}));
223             }
224             else
225             {
226 0         0 $args->{protocol} = $args->{agent}->protocol;
227             }
228             }
229              
230             # All protocols are all-uppercase, so just make sure as we assign it
231 14   33     1449 $protocol{$id} = uc $args->{protocol} || $self->get_default_protocol;
232 14         46 $agent{$id} = $args->{agent};
233             # Fall back to the defaults here
234 14 100       82 $api_key{$id} = $self->get_default_api_key unless $args->{api_key};
235 14 50       89 $agent_args{$id} = $self->get_default_agent_args unless $args->{agent_args};
236             # Remove these so they aren't further processed
237 14         32 delete @$args{qw(protocol agent)};
238              
239 14         44 return;
240             }
241              
242             ###############################################################################
243             #
244             # Sub Name: get_type
245             #
246             # Description: Return the generic type of the object, versus the actual
247             # class.
248             #
249             # Arguments: NAME IN/OUT TYPE DESCRIPTION
250             # $class in scalar Class name or object
251             #
252             # Globals: %TYPES
253             # %type
254             #
255             # Returns: Type
256             #
257             ###############################################################################
258             sub get_type
259             {
260 6     6 1 486 my $class = shift;
261              
262 6         14 my $type = '';
263              
264 6 50       23 if (ref $class)
265             {
266 6         31 $type = $type{ident $class};
267             }
268             else
269             {
270 0         0 $type = $class->new({})->get_type;
271             }
272              
273 6         36 $type;
274             }
275              
276             ###############################################################################
277             #
278             # Sub Name: add_type
279             #
280             # Description: Add a name-to-class mapping for the factory nature of this
281             # class' constructor.
282             #
283             # Arguments: NAME IN/OUT TYPE DESCRIPTION
284             # $class in scalar Ignored-- this can be a static
285             # method or not.
286             # $type in scalar The type name, usually the last
287             # element of the classname with
288             # a leading cap (e.g. Books).
289             # $pack in scalar The package that should be
290             # instantiated for the type.
291             #
292             # Globals: @TYPES
293             # %TYPES
294             #
295             # Returns: Success: $pack (for chaining purposes)
296             # Failure: Throws Error::Simple
297             #
298             ###############################################################################
299             sub add_type
300             {
301 1     1 1 2 my ($class, $type, $pack) = @_;
302              
303 1 50       4 throw Error::Simple("No package specfied for $type") unless $pack;
304              
305 1         2 push(@TYPES, $type);
306 1         4 $TYPES{$type} = $pack;
307             }
308              
309             ###############################################################################
310             #
311             # Sub Name: remove_type
312             #
313             # Description: Delete the given type from the map.
314             #
315             # Arguments: NAME IN/OUT TYPE DESCRIPTION
316             # $class in scalar Ignored-- this can be a static
317             # method or not.
318             # $type in scalar The type name, usually the last
319             # element of the classname with
320             # a leading cap (e.g. Books).
321             #
322             # Globals: @TYPES
323             # %TYPES
324             # CORETYPES
325             #
326             # Returns: Success: void
327             # Failure: throws Error::Simple if $type is in @CORETYPES
328             #
329             ###############################################################################
330             sub remove_type
331             {
332 2     2 1 5 my ($class, $type) = @_;
333              
334 2 100       23 throw Error::Simple("Cannot remove a core type")
335             if (grep($_ eq $type, (CORETYPES)));
336 1         2 delete $TYPES{$type};
337 1         6 @TYPES = grep($_ ne $type, @TYPES);
338              
339 1         3 return;
340             }
341              
342             ###############################################################################
343             #
344             # Sub Name: class_for_type
345             #
346             # Description: Return the actual class that should be used to instantiate
347             # the given type.
348             #
349             # Arguments: NAME IN/OUT TYPE DESCRIPTION
350             # $class in scalar Ignored-- this can be a static
351             # method or not.
352             # $type in scalar Type to look up.
353             #
354             # Globals: %TYPES
355             #
356             # Returns: Success: class name
357             # Failure: undef
358             #
359             ###############################################################################
360             sub class_for_type
361             {
362 7     7 1 2727 my ($class, $type) = @_;
363              
364 7         36 $TYPES{$type};
365             }
366              
367             ###############################################################################
368             #
369             # Sub Name: get_api_key
370             #
371             # Description: Return the object's API key, or the default one if called
372             # statically.
373             #
374             # Arguments: NAME IN/OUT TYPE DESCRIPTION
375             # $self in ref Object or class name
376             #
377             # Globals: %api_key
378             # $DEFAULTS
379             #
380             # Returns: API key
381             #
382             ###############################################################################
383             sub get_api_key
384             {
385 7     7 1 62 my $self = shift;
386              
387 7 50       64 ref($self) ? $api_key{ident $self} : $self->get_default_api_key;
388             }
389              
390             ###############################################################################
391             #
392             # Sub Name: get_protocol
393             #
394             # Description: Return the object's protocol, or the default one if called
395             # statically.
396             #
397             # Arguments: NAME IN/OUT TYPE DESCRIPTION
398             # $self in ref Object or class name
399             #
400             # Globals: %protocol
401             # $DEFAULTS
402             #
403             # Returns: protocol string
404             #
405             ###############################################################################
406             sub get_protocol
407             {
408 8     8 1 3006 my $self = shift;
409              
410 8 100       76 ref($self) ? $protocol{ident $self} : $self->get_default_protocol;
411             }
412              
413             ###############################################################################
414             #
415             # Sub Name: set_protocol
416             #
417             # Description: Set the protocol, and possibly the agent, on the object
418             #
419             # Arguments: NAME IN/OUT TYPE DESCRIPTION
420             # $self in ref Object of/derived from this
421             # class
422             # $proto in scalar New protocol value
423             # $agent in ref If passed, a new agent. Agent's
424             # protocol() method must
425             # validate $proto.
426             #
427             # Globals: %protocol
428             #
429             # Returns: Success: $self
430             # Failure: Throws Error::Simple
431             #
432             ###############################################################################
433             sub set_protocol
434             {
435 0     0 1 0 my ($self, $proto, $agent) = @_;
436              
437             # Make sure $proto is all-uppercase
438 0         0 $proto = uc $proto;
439              
440 0         0 $protocol{ident $self} = $proto;
441             # set_agent() tests the object's value of protocol against itself, so this
442             # must be done after we've altered %protocol.
443 0 0       0 $self->set_agent($agent) if $agent;
444              
445 0         0 $self;
446             }
447              
448             ###############################################################################
449             #
450             # Sub Name: get_agent
451             #
452             # Description: Return the agent object for the calling object. The agent
453             # object's creation is delayed until the first such request.
454             #
455             # Arguments: NAME IN/OUT TYPE DESCRIPTION
456             # $self in ref Object
457             #
458             # Globals: %agent
459             #
460             # Returns: Success: Object that is a (or derives from)
461             # WebService::ISBNDB::Agent
462             # Failure: throws Error::Simple
463             #
464             ###############################################################################
465             sub get_agent
466             {
467 7     7 1 28 my $self = shift;
468              
469 7         22 my $id = ident $self;
470 7 100       34 my $agent = $id ? $agent{$id} : $self->get_default_agent;
471              
472 7 100       29 unless ($agent)
473             {
474 6         18 my $agent_args;
475 6 50       30 $agent_args = $agent_args{$id} if $id;
476 6 50       33 $agent_args = $self->get_default_agent_args unless $agent_args;
477 6         10 my $protocol;
478 6 50       25 $protocol = $protocol{$id} if $id;
479 6 50       25 $protocol = $self->get_default_protocol unless $protocol;
480              
481             # new() in WebService::ISBNDB::Agent also acts as a factory
482 6         69 $agent = WebService::ISBNDB::Agent->new($protocol,
483             { agent_args => $agent_args });
484 1 50       88 $agent{$id} = $agent if ($id);
485             }
486              
487 2         6 $agent;
488             }
489              
490             ###############################################################################
491             #
492             # Sub Name: set_agent
493             #
494             # Description: Manually set the agent instance for this object.
495             #
496             # Arguments: NAME IN/OUT TYPE DESCRIPTION
497             # $self in ref Object
498             # $agent in ref New agent object. Must derive
499             # from
500             # WebService::ISBNDB::Agent.
501             #
502             # Globals: %agent
503             #
504             # Returns: Success: $self
505             # Failure: throws Error::Simple
506             #
507             ###############################################################################
508             sub set_agent
509             {
510 0     0 1 0 my ($self, $agent) = @_;
511              
512 0 0 0     0 throw Error::Simple("New agent must derive from WebService::ISBNDB::Agent")
513             unless (ref $agent and $agent->isa('WebService::ISBNDB::Agent'));
514 0 0       0 throw Error::Simple("New agent does not match object's declared protocol" .
515             ' (' . $self->get_protocol . ')')
516             unless $agent->protocol($self->get_protocol);
517              
518 0         0 $agent{ident $self} = $agent;
519              
520 0         0 $self;
521             }
522              
523             ###############################################################################
524             #
525             # Sub Name: set_type
526             #
527             # Description: Setter for the type attribute, marked RESTRICTED so that
528             # it can only be used here and in subclasses.
529             #
530             # Arguments: NAME IN/OUT TYPE DESCRIPTION
531             # $self in ref Object
532             # $type in scalar Type value
533             #
534             # Globals: %type
535             #
536             # Returns: $self
537             #
538             ###############################################################################
539             sub set_type : RESTRICTED
540             {
541 24     0 0 387 my ($self, $type) = @_;
542              
543 24         84 $type{ident $self} = $type;
544              
545 24         44 $self;
546 10     10   82 }
  10         17  
  10         85  
547              
548             ###############################################################################
549             #
550             # Sub Name: find
551             #
552             # Description: Find a single entity, based on the first argument (which
553             # identifies the type).
554             #
555             # Arguments: NAME IN/OUT TYPE DESCRIPTION
556             # $self in ref Object
557             # @args in array Variable, depending on $self.
558             # See text.
559             #
560             # Globals: %TYPES
561             #
562             # Returns: Success: $self or new object
563             # Failure: throws Error::Simple
564             #
565             ###############################################################################
566             sub find
567             {
568 5     5 1 16 my ($self, @args) = @_;
569              
570             # If $self is/points to the API class, then the first element of @args has
571             # to be the name of a data class, and we defer to its find() method with
572             # the remainder of @args.
573 5 50       38 if ($self->get_type eq 'API')
574             {
575 0         0 my $type = shift(@args);
576 0 0       0 throw Error::Simple("find: Unknown factory type '$type'")
577             unless ($type = $self->class_for_type($type));
578 0         0 eval "require $type;";
579 0         0 return $type->find(@args);
580             }
581              
582             # If it isn't, just fall through to the semi-private _find()
583 5         32 $self->_find($self->normalize_args(@args));
584             }
585              
586             ###############################################################################
587             #
588             # Sub Name: _find
589             #
590             # Description: Actual find() implementation. Calls in to the correct
591             # request_{all|single} method of the agent this object has
592             # allocated.
593             #
594             # Arguments: NAME IN/OUT TYPE DESCRIPTION
595             # $self in ref Object or class
596             # $args in hashref Hash reference of the arguments
597             # for the find operation.
598             #
599             # Returns: Success: New object
600             # Failure: throws Error::Simple
601             #
602             ###############################################################################
603             sub _find : PRIVATE
604             {
605 5     0   43 my ($self, $args) = @_;
606              
607 5         47 $self->get_agent->request_single($self, $args);
608 10     10   3921 }
  10         16  
  10         38  
609              
610             ###############################################################################
611             #
612             # Sub Name: search
613             #
614             # Description: Find zero or more entities, based on the criteria
615             # provided. If this is called from the API class, the first
616             # argument might identify the type.
617             #
618             # Arguments: NAME IN/OUT TYPE DESCRIPTION
619             # $self in ref Object
620             # @args in array Variable, depending on $self.
621             # See text.
622             #
623             # Globals: %TYPES
624             #
625             # Returns: Success: $self or new object
626             # Failure: throws Error::Simple
627             #
628             ###############################################################################
629             sub search
630             {
631 0     0 1 0 my ($self, @args) = @_;
632              
633             # If $self is/points to the API class, then the first element of @args has
634             # to be the name of a data class, and we defer to its search() method with
635             # the remainder of @args.
636 0 0       0 if ($self->get_type eq 'API')
637             {
638 0         0 my $type = shift(@args);
639 0 0       0 throw Error::Simple("search: Unknown factory type '$type'")
640             unless ($type = $self->class_for_type($type));
641 0         0 eval "require $type;";
642 0         0 $args[0]->{api_key} = $self->get_api_key;
643 0         0 return $type->search(@args);
644             }
645              
646             # Otherwise, fall-through to the semi-private _search().
647 0         0 $self->_search($self->normalize_args(@args));
648             }
649              
650             ###############################################################################
651             #
652             # Sub Name: _search
653             #
654             # Description: Actual search() implementation. Calls in to the correct
655             # request_{all|single} method of the agent this object has
656             # allocated.
657             #
658             # Arguments: NAME IN/OUT TYPE DESCRIPTION
659             # $self in ref Object or class
660             # $args in hashref Hash reference of the arguments
661             # for the find operation.
662             #
663             # Returns: Success: List-reference of zero+ objects
664             # Failure: throws Error::Simple
665             #
666             ###############################################################################
667             sub _search : PRIVATE
668             {
669 0     0   0 my ($self, $args) = @_;
670              
671 0         0 $self->get_agent->request_all($self, $args);
672 10     10   3483 }
  10         17  
  10         56  
673              
674             ###############################################################################
675             #
676             # Sub Name: normalize_args
677             #
678             # Description: Hook routine for sub-classes to override; allows for
679             # translation of the keys in $args to the form needed by
680             # the service.
681             #
682             # Arguments: NAME IN/OUT TYPE DESCRIPTION
683             # $class in scalar Ignored
684             # $args in hashref Returned unaltered
685             #
686             # Returns: $args, without change
687             #
688             ###############################################################################
689             sub normalize_args
690             {
691 0     0 1 0 $_[1];
692             }
693              
694             ###############################################################################
695             #
696             # Sub Name: get_default_protocol
697             #
698             # Description: Return the current value of the default protocol
699             #
700             # Arguments: All ignored
701             #
702             # Globals: %DEFAULTS
703             #
704             # Returns: $DEFAULTS{protocol}
705             #
706             ###############################################################################
707             sub get_default_protocol
708             {
709 17     17 1 98 $DEFAULTS{protocol};
710             }
711              
712             ###############################################################################
713             #
714             # Sub Name: set_default_protocol
715             #
716             # Description: Set a new value for the default protocol
717             #
718             # Arguments: NAME IN/OUT TYPE DESCRIPTION
719             # $class in scalar Ignored
720             # $proto in scalar New protocol value; forced UC
721             #
722             # Globals: $DEFAULTS{protocol}
723             #
724             # Returns: void
725             #
726             ###############################################################################
727             sub set_default_protocol
728             {
729 7     7 1 11958 my ($class, $proto) = @_;
730              
731 7         29 $DEFAULTS{protocol} = uc $proto;
732 7         19 return;
733             }
734              
735             ###############################################################################
736             #
737             # Sub Name: get_default_api_key
738             #
739             # Description: Return the current value of the default API key
740             #
741             # Arguments: All ignored
742             #
743             # Globals: %DEFAULTS
744             #
745             # Returns: $DEFAULTS{api_key}
746             #
747             ###############################################################################
748             sub get_default_api_key
749             {
750 14     14 1 44 $DEFAULTS{api_key};
751             }
752              
753             ###############################################################################
754             #
755             # Sub Name: set_default_api_key
756             #
757             # Description: Set a new value for $default_api_key
758             #
759             # Arguments: NAME IN/OUT TYPE DESCRIPTION
760             # $class in scalar Ignored
761             # $api_key in scalar New API key value
762             #
763             # Globals: %DEFAULTS
764             #
765             # Returns: void
766             #
767             ###############################################################################
768             sub set_default_api_key
769             {
770 7     7 1 653 my ($class, $api_key) = @_;
771              
772 7         26 $DEFAULTS{api_key} = $api_key;
773 7         19 return;
774             }
775              
776             ###############################################################################
777             #
778             # Sub Name: get_default_agent
779             #
780             # Description: Retrieve the default agent (LWP::UserAgent) object
781             #
782             # Arguments: NAME IN/OUT TYPE DESCRIPTION
783             # $class in scalar Class called from
784             #
785             # Globals: %DEFAULTS
786             #
787             # Returns: $DEFAULTS{agent}
788             #
789             ###############################################################################
790             sub get_default_agent
791             {
792 3     3 1 5 my $class = shift;
793              
794 3 100       91 unless ($DEFAULTS{agent})
795             {
796 2         8 $DEFAULTS{agent} =
797             WebService::ISBNDB::Agent->new($class->get_protocol(),
798             { agent_args =>
799             $DEFAULTS{agent_args} });
800             }
801              
802 3         128 $DEFAULTS{agent};
803             }
804              
805             ###############################################################################
806             #
807             # Sub Name: set_default_agent
808             #
809             # Description: Set a new value for the default agent. Tests to see if it
810             # is a derivative of LWP::UserAgent.
811             #
812             # Arguments: NAME IN/OUT TYPE DESCRIPTION
813             # $class in scalar Ignored
814             # $agent in ref New agent value
815             #
816             # Globals: %DEFAULTS
817             #
818             # Returns: Success: void
819             # Failure: throws Error::Simple
820             #
821             ###############################################################################
822             sub set_default_agent
823             {
824 1     1 1 3 my ($class, $agent) = @_;
825              
826 1 0 0     3 throw Error::Simple("Argument to 'set_default_agent' must be an object " .
      33        
827             "of or derived from LWP::UserAgent")
828             unless (! defined $agent or
829             (ref $agent and $agent->isa('LWP::UserAgent')));
830              
831 1         4 $DEFAULTS{agent} = $agent;
832 1         2 return;
833             }
834              
835             ###############################################################################
836             #
837             # Sub Name: get_default_agent_args
838             #
839             # Description: Retrieve the default agent args
840             #
841             # Arguments: NAME IN/OUT TYPE DESCRIPTION
842             # $class in scalar Ignored
843             #
844             # Globals: %DEFAULTS
845             #
846             # Returns: $DEFAULTS{agent_args}
847             #
848             ###############################################################################
849             sub get_default_agent_args
850             {
851 14     14 1 38 $DEFAULTS{agent_args};
852             }
853              
854             ###############################################################################
855             #
856             # Sub Name: set_default_agent_args
857             #
858             # Description: Set a new value for the default agent arguments. Tests to
859             # see that it is a has reference.
860             #
861             # Arguments: NAME IN/OUT TYPE DESCRIPTION
862             # $class in scalar Ignored
863             # $agent_args in ref New agent_args value
864             #
865             # Globals: %DEFAULTS
866             #
867             # Returns: Success: void
868             # Failure: throws Error::Simple
869             #
870             ###############################################################################
871             sub set_default_agent_args
872             {
873 1     1 1 2 my ($class, $agent_args) = @_;
874              
875 1 50       5 throw Error::Simple("Argument to 'set_default_agent_args' must be a " .
876             "hash-reference")
877             unless (ref($agent_args) eq 'HASH');
878              
879 1         2 $DEFAULTS{agent_args} = $agent_args;
880 1         2 return;
881             }
882              
883             ###############################################################################
884             #
885             # Sub Name: copy
886             #
887             # Description: Copy attributes from the target object to the caller.
888             #
889             # Arguments: NAME IN/OUT TYPE DESCRIPTION
890             # $self in ref Object
891             # $target in ref Object of the same class
892             #
893             # Globals: %protocol
894             # %api_key
895             # %type
896             #
897             # Returns: Success: void
898             # Failure: throws Error::Simple
899             #
900             ###############################################################################
901             sub copy : CUMULATIVE
902             {
903 0     0 1 0 my ($self, $target) = @_;
904              
905 0 0       0 throw Error::Simple("Argument to 'copy' must be the same class as caller")
906             unless (ref($self) eq ref($target));
907              
908 0         0 my $id1 = ident $self;
909 0         0 my $id2 = ident $target;
910              
911 0         0 $protocol{$id1} = $protocol{$id2};
912 0         0 $api_key{$id1} = $api_key{$id2};
913 0         0 $type{$id1} = $type{$id2};
914              
915 0         0 return;
916 10     10   6813 }
  10         33  
  10         74  
917              
918             1;
919              
920             =pod
921              
922             =head1 NAME
923              
924             WebService::ISBNDB::API - Base class for the WebService::ISBNDB API classes
925              
926             =head1 SYNOPSIS
927              
928             require WebService::ISBNDB::API;
929              
930             $handle = WebService::ISBNDB::API->new({ protocol => REST =>
931             api_key => $key });
932              
933             $book = $handle->new(Books => { isbn => '0596002068' });
934             $all_lotr = $handle->search(Books =>
935             { title => 'lord of the rings ' });
936              
937             =head1 DESCRIPTION
938              
939             The B class is the base for the classes that handle
940             books, publishers, authors, categories and subjects. It also acts as a
941             factory-class for instantiating those other classes. Any of the data classes
942             can be created from the constructor of this class, using the syntax described
943             below.
944              
945             This class manages the common elements of the data classes, including the
946             handling of the communication agent used to make requests of B.
947             This class (and all sub-classes of it) are based on the B
948             inside-out objects pattern. See L for more detail.
949              
950             All error conditions in the methods of this class are handled using the
951             exception model provided by the B module. Most errors are thrown in
952             the form of B exception objects. See L for more
953             detail.
954              
955             =head1 USING THE ISBNDB.COM SERVICE
956              
957             In order to access the B web service programmatically, you must
958             first register an account on their site (see
959             L) and then create an access key.
960             You can create more than one key, as needed. All the API calls require the
961             access key be part of the parameters.
962              
963             More information is available at L. You can also view the
964             documentation for their API at L.
965              
966             =head1 METHODS
967              
968             The following methods are provided by this class, usable by all derived
969             classes. Private methods are not documented here.
970              
971             =head2 Constructor
972              
973             The constructor for this class behaves a little differently than the default
974             constructor provided by B.
975              
976             =over 4
977              
978             =item new([ $TYPE, ] $ARGS)
979              
980             Constructs a new object, returning the referent. The value of C<$ARGS> is a
981             hash-reference of key/value pairs that correspond to the attributes for the
982             class. If C<$TYPE> is provided, then the value must match one of the known
983             data-types, and the new object will be created from that class rather than
984             B. Likewise, C<$ARGS> will be passed to that class'
985             constructor and not processed at all by this one.
986              
987             If C<$TYPE> is not a known type (see L), then an exception
988             of type B is thrown.
989              
990             =back
991              
992             The class also defines:
993              
994             =over 4
995              
996             =item copy($TARGET)
997              
998             Copies the target object into the calling object. All attributes (including
999             the ID) are copied. This method is marked "CUMULATIVE" (see L),
1000             and any sub-class of this class should provide their own copy() and also mark
1001             it "CUMULATIVE", to ensure that all attributes at all levels are copied.
1002              
1003             =back
1004              
1005             This method copies only the basic attributes. Each of the implementation
1006             classes must provide additional copy() methods (also marked "CUMULATIVE") to
1007             ensure that all attributes are copied.
1008              
1009             =head2 Accessors
1010              
1011             The accessor methods are used to set and retrieve the attributes (instance
1012             data) stored on the object. While a few of them have special behavior, most
1013             operate as simple get or set accessors as described in L. The
1014             attributes for this class are:
1015              
1016             =over 4
1017              
1018             =item protocol
1019              
1020             This attribute identifies the communication protocol this object will use for
1021             making requests of the B service. The value for it is always
1022             forced to upper-case, as all protocols are regarded in that manner.
1023             (See L.)
1024              
1025             =item api_key
1026              
1027             To use the B service, you must register on their web site and
1028             obtain an API key. The key must be used on all data requests to their API.
1029             This attribute stores the API key to be used on all requests made by the
1030             object. (See L.)
1031              
1032             =item agent
1033              
1034             This attribute stores the object used for communicating with the service.
1035             The value must be a sub-class of the B class.
1036             (See L.)
1037              
1038             =item agent_args
1039              
1040             When the B-based object is instantiated, any
1041             arguments stored in this attribute will be passed to the constructor. If set,
1042             this attribute's value must be a hash-reference (otherwise the constructor
1043             will throw an exception). (See L.)
1044              
1045             =item type
1046              
1047             This attribute is read-only by users that are not sub-classes of this class.
1048             It identifies the class-type of the object, which is generally the last
1049             element of the class name (C, C, etc.). It allows the
1050             B sub-classes to make choices based on the type of
1051             the object. ("Type" in this context should not be confused with "types" as
1052             they pertain to mapping books, publishers, etc. to specific data classes.)
1053              
1054             =back
1055              
1056             The following accessor methods are provided by this class:
1057              
1058             =over 4
1059              
1060             =item get_protocol
1061              
1062             Retrieve the current value of the protocol attribute.
1063              
1064             =item set_protocol($PROTO [ , $AGENT ])
1065              
1066             Set the protocol to use for communication. Optionally, you can also provide
1067             an agent instance at the same time, and set both values. If an agent is
1068             specified, it will be tested against the new protocol value, to make sure it
1069             works with that protocol. If the agent does not match the protocol, an
1070             exception will be thrown.
1071              
1072             =item get_api_key
1073              
1074             Retrieve the current API key.
1075              
1076             =item set_api_key
1077              
1078             Set the API key to use when contacting the service. If this value is not
1079             recognized by the B service, you will not be able to retrieve any
1080             data.
1081              
1082             =item get_agent
1083              
1084             Retrieve the current B-derived object used for
1085             communication. Unless the agent was explicitly provided as an argument to
1086             the constructor, the agent object is constructed lazily: it is only
1087             instantiated upon the first call to this method.
1088              
1089             =item set_agent
1090              
1091             Set a new agent object for use when this object makes requests from the
1092             service. An agent object must derive from the B
1093             class (that class itself cannot act as an agent). When a new agent is
1094             assigned, its B method is called with the current value of the
1095             C attribute of the object, to ensure that the agent matches the
1096             protocol. If not, an exception is thrown.
1097              
1098             =item get_agent_args
1099              
1100             Get the arguments that are to be passed to agent-instantiation.
1101              
1102             =item set_agent_args
1103              
1104             Provide a new set of arguments to be used when instantiating an agent object.
1105             The value must be a hash reference, or the constructor for the agent class
1106             will thrown an exception.
1107              
1108             =item get_type
1109              
1110             Get the class' "type". In most cases, this is the last component of the
1111             class name. Note that there is no set-accessor for this attribute; it cannot
1112             be set by outside users.
1113              
1114             =back
1115              
1116             =head2 Default Attribute Values
1117              
1118             In addition to the above, the following accessors are provided to allow
1119             users to set default values for the protocol, the API key, the agent and the
1120             defaut arguments for agent construction. This allows you
1121             to set these once, at the start of the application, and not have to pass them
1122             to every new object instantiation:
1123              
1124             =over 4
1125              
1126             =item set_default_protocol($PROTO)
1127              
1128             Sets the default protocol to the value of C<$PROTO>. Unlike the API key, there
1129             is already a default value for this when the module is loaded (B).
1130              
1131             =item get_default_protocol
1132              
1133             Returns the current default protocol.
1134              
1135             =item set_default_api_key($KEY)
1136              
1137             Sets a new default API key. There is no built-in default for this, so you must
1138             either call this, set it via module-import (see below), or provide the key
1139             value for each individual object creation.
1140              
1141             =item get_default_api_key
1142              
1143             Returns the current default API key.
1144              
1145             =item set_default_agent($AGENT)
1146              
1147             Sets a new value for the default agent. Any object created without an C
1148             attribute will inherit this value. The value must be an instance of
1149             B or a derivative class.
1150              
1151             =item get_default_agent
1152              
1153             Get the default agent. If it hasn't been set the first time this is called,
1154             one is created (possibly using the default agent arguments).
1155              
1156             =item set_default_agent_args($ARGS)
1157              
1158             Sets a new value for the default arguments to agent creation. Any time an
1159             agent is created without the object having an explicit value for arguments
1160             to pass, this value is read and used. The value must be a hash reference.
1161              
1162             =item get_default_agent_args
1163              
1164             Get the set of default agent arguments, if any.
1165              
1166             =back
1167              
1168             Besides using these accessors to provide the defaults, you can also specify
1169             them when loading the module:
1170              
1171             use WebService::ISBNDB::API (api_key => 'abc123');
1172              
1173             C, C, C and C are recognized at
1174             use-time.
1175              
1176             =head2 Managing Types
1177              
1178             As the root of the data-class hierarchy, this package also provides the
1179             methods for managing the data-types known to the overall module.
1180              
1181             The built-in data-types are:
1182              
1183             =over 4
1184              
1185             =item Authors
1186              
1187             This type covers the author data structures returned by B. It is
1188             covered in detail in L.
1189             =item Books
1190              
1191             This type covers the book data structures returned by B. It is
1192             covered in detail in L.
1193              
1194             =item Categories
1195              
1196             This type covers the category data structures returned by B. It
1197             is covered in detail in L.
1198              
1199             =item Publishers
1200              
1201             This type covers the publisher data structures returned by B. It
1202             is covered in detail in L.
1203              
1204             =item Subjects
1205              
1206             This type covers the subject data structures returned by B. It is
1207             covered in detail in L.
1208              
1209             =back
1210              
1211             Note that the types are case-sensitive.
1212              
1213             The following methods operate on the internal types map:
1214              
1215             =over 4
1216              
1217             =item add_type($TYPE, $CLASS)
1218              
1219             Add a mapping for the type specified by C<$TYPE> to the class specified in
1220             C<$CLASS>. C<$TYPE> may be one of the core types listed above; if so, then the
1221             new class will override the built-in class for that type. You cannot remove
1222             a type/class mapping for any of the core types; you can only re-override them
1223             by calling the method again. If you want to temporarily redirect a type, you
1224             must save the original value (using B) and manually restore it
1225             by called B again.
1226              
1227             =item class_for_type($TYPE)
1228              
1229             Returns the class-name for the given C<$TYPE>. Throws an exception if C<$TYPE>
1230             is not in the mapping table.
1231              
1232             =item remove_type($TYPE)
1233              
1234             Removes the type/class mapping for the given C<$TYPE>. Note that you cannot
1235             remove the mappings for any of the core types listed above, even if you have
1236             already overridden them with B. If you pass any of the core types,
1237             an exception will be thrown.
1238              
1239             =back
1240              
1241             All of the type-map methods may be called as static methods.
1242              
1243             =head2 Retrieving Data
1244              
1245             B and its sub-classes support the retrieval of data
1246             in two ways: single-record and searching.
1247              
1248             Single-record retrieval is for getting just one result from the service,
1249             usually from a known unique key (such as fetching a book by the ISBN). The
1250             interface for it always returns a single result, even when the criteria are
1251             not specific-enough and more than one record is returned. In these cases, the
1252             first record is used and the rest discarded.
1253              
1254             Searching returns zero or more results from a search of the service using the
1255             provided criteria. Presently, the return is in the form of a list-reference
1256             (even when the result-set has only one element or no elements). This will
1257             change in the future, to an object-base result-set that offers iterators and
1258             delayed-loading of results.
1259              
1260             The data-retrieving methods are:
1261              
1262             =over 4
1263              
1264             =item find($TYPE, $IDENT|$ARGS)
1265              
1266             Finds a single record, using either a scalar identifying value (C<$IDENT>) or
1267             a hash reference (C<$ARGS>) with one or more key/value pairs. The value of
1268             C<$TYPE> tells C) which data class to do the
1269             find-operation on. If the value is not a known type, an exception is thrown.
1270              
1271             How the scalar value C<$IDENT> is used in the data-retrieval is dependent on
1272             the value of C<$TYPE>. See the documentation for the various data classes
1273             for more detail.
1274              
1275             =item search($TYPE, $ARGS)
1276              
1277             Search for items of type C<$TYPE> using the key/value pairs in the hash
1278             reference C<$ARGS>. C<$ARGS> must be a hash reference, there is no corner-case
1279             for a scalar as with B.
1280              
1281             =item normalize_args($ARGS)
1282              
1283             In this class, this method does nothing. It is available for sub-classes to
1284             overload. If a class overloads it, the requirement is that any changes to the
1285             arguments be made in-place, altering C<$ARGS>, and that the return value be
1286             either C<$ARGS> itself or a copy.
1287              
1288             The purpose of this method is to allow implementation classes to make any
1289             translation of user-space argument names to the names used by B.
1290             Most of the implementation classes also use it to add more arguments in order
1291             to retrieve extra data from the service.
1292              
1293             =back
1294              
1295             These methods may be called as static methods.
1296              
1297             =head1 CAVEATS
1298              
1299             The data returned by this class is only as accurate as the data retrieved from
1300             B.
1301              
1302             The list of results from calling search() is currently limited to 10 items.
1303             This limit will be removed in an upcoming release, when iterators are
1304             implemented.
1305              
1306             =head1 SEE ALSO
1307              
1308             L, L, L,
1309             L, L,
1310             L,
1311             L, L
1312              
1313             =head1 AUTHOR
1314              
1315             Randy J. Ray Erjray@blackperl.comE
1316              
1317             =head1 LICENSE
1318              
1319             This module and the code within are
1320             released under the terms of the Artistic License 2.0
1321             (http://www.opensource.org/licenses/artistic-license-2.0.php). This
1322             code may be redistributed under either the Artistic License or the GNU
1323             Lesser General Public License (LGPL) version 2.1
1324             (http://www.opensource.org/licenses/lgpl-license.php).
1325              
1326             =cut