File Coverage

blib/lib/RPC/XML/Procedure.pm
Criterion Covered Total %
statement 124 261 47.5
branch 37 94 39.3
condition 11 35 31.4
subroutine 25 38 65.7
pod 14 16 87.5
total 211 444 47.5


line stmt bran cond sub pod time code
1             ###############################################################################
2             #
3             # This file copyright (c) 2001-2011 Randy J. Ray, all rights reserved
4             #
5             # Copying and distribution are permitted under the terms of the Artistic
6             # License 2.0 (http://www.opensource.org/licenses/artistic-license-2.0.php) or
7             # the GNU LGPL (http://www.opensource.org/licenses/lgpl-2.1.php).
8             #
9             ###############################################################################
10             #
11             # Description: This class abstracts out all the procedure-related
12             # operations from the RPC::XML::Server class. It also
13             # provides the RPC::XML::Method and RPC::XML::Function
14             # namespaces.
15             #
16             # Functions: new
17             # name \
18             # code \
19             # signature \ These are the accessor functions for the
20             # help / data in the object, though it's visible.
21             # version /
22             # hidden /
23             # clone
24             # add_signature
25             # delete_signature
26             # make_sig_table
27             # match_signature
28             # reload
29             # load_xpl_file
30             # call
31             #
32             # Libraries: XML::Parser (used only on demand in load_xpl_file)
33             # File::Spec
34             #
35             # Global Consts: $VERSION
36             #
37             # Environment: None.
38             #
39             ###############################################################################
40              
41             # Perl::Critic:
42             #
43             # We use explicit @ISA in RPC::XML::Method and RPC::XML::Function because it
44             # is faster than doing 'use base' when we're already in the same file.
45              
46             ## no critic (ProhibitExplicitISA)
47              
48             package RPC::XML::Procedure;
49              
50 10     10   20366 use 5.008008;
  10         20  
  10         303  
51 10     10   37 use strict;
  10         13  
  10         203  
52 10     10   33 use warnings;
  10         13  
  10         236  
53 10     10   35 use vars qw($VERSION %VALID_TYPES);
  10         12  
  10         402  
54              
55 10     10   40 use File::Spec;
  10         12  
  10         153  
56 10     10   29 use Scalar::Util 'blessed';
  10         7  
  10         375  
57              
58 10     10   420 use RPC::XML 'smart_encode';
  10         13  
  10         16530  
59              
60             # This module also provides RPC::XML::Method and RPC::XML::Function
61             ## no critic (ProhibitMultiplePackages)
62              
63             $VERSION = '1.30';
64             $VERSION = eval $VERSION; ## no critic (ProhibitStringyEval)
65              
66             # This should match the set of type-classes defined in RPC::XML.pm. Note that
67             # we use "dateTime.iso8601" instead of "datetime_iso8601", because that is how
68             # it has to be in the signature.
69             %VALID_TYPES = map { $_ => 1 }
70             (qw(int i4 i8 double string boolean dateTime.iso8601 nil array struct
71             base64));
72              
73             ###############################################################################
74             #
75             # Sub Name: new
76             #
77             # Description: Create a new object of this class, storing the info on
78             # regular keys (no obfuscation used here).
79             #
80             # Arguments: NAME IN/OUT TYPE DESCRIPTION
81             # $class in scalar Class to bless into
82             # @argz in variable Disposition is variable; see
83             # below
84             #
85             # Returns: Success: object ref
86             # Failure: error string
87             #
88             ###############################################################################
89             sub new
90             {
91 17     17 1 3418 my ($class , @argz) = @_;
92              
93 17         18 my $new_proc; # This will be a hashref that eventually gets blessed
94              
95 17 100       37 if (ref $class)
96             {
97 1         3 return __PACKAGE__ . '::new: Must be called as a static method';
98             }
99              
100             # There are three things that @argz could be:
101 16 100       47 if (ref $argz[0])
    100          
102             {
103             # 1. A hashref containing all the relevant keys
104              
105             # Start wtih the defaults for the optional keys
106 10         32 $new_proc = {
107             namespace => q{},
108             version => 0,
109             hidden => 0,
110             help => q{},
111             };
112             # Copy everything from the hash, don't try to use it directly
113 10         11 for (keys %{$argz[0]}) { $new_proc->{$_} = $argz[0]->{$_} }
  10         32  
  25         38  
114             }
115             elsif (@argz == 1)
116             {
117             # 2. Exactly one non-ref element, a file to load
118              
119             # Loading code from an XPL file, it can actually be of a type other
120             # than how this constructor was called. So what we are going to do is
121             # this: If $class is RPC::XML::Procedure, act like a factory method
122             # and return whatever the file claims to be. Otherwise, the file has
123             # to match $class or it's an error.
124 4         17 ($new_proc, my $pkg) = load_xpl_file($argz[0]);
125 0 0       0 if (! ref $new_proc)
126             {
127             # load_xpl_path signalled an error
128 0         0 return $new_proc;
129             }
130 0 0 0     0 if ($class ne 'RPC::XML::Procedure' && $pkg ne $class)
131             {
132 0         0 return "${class}::new: File loaded ($argz[0]) must match " .
133             'this calling class';
134             }
135              
136 0         0 $class = $pkg;
137             }
138             else
139             {
140             # 3. If there is more than one arg, it's a sort-of-hash. That is, the
141             # key 'signature' is allowed to repeat.
142 2         3 my ($key, $val);
143 2         14 $new_proc = {
144             namespace => q{},
145             version => 0,
146             hidden => 0,
147             help => q{},
148             signature => [],
149             };
150 2         4 while (@argz)
151             {
152 11         12 ($key, $val) = splice @argz, 0, 2;
153 11 100       13 if ($key eq 'signature')
154             {
155             # Since there may be more than one signature, we allow it to
156             # repeat. Of course, that's also why we can't just take @argz
157             # directly as a hash. *shrug*
158 4         8 push @{$new_proc->{signature}},
  2         6  
159 4 100       3 ref $val ? join q{ } => @{$val} : $val;
160             }
161             else
162             {
163 7         12 $new_proc->{$key} = $val;
164             }
165             }
166             }
167              
168             # A sanity check on the content of the object before we bless it:
169 12 100 100     54 if (! ($new_proc->{name} && $new_proc->{code}))
170             {
171 2         7 return "${class}::new: Missing required data (name or code)";
172             }
173 10 100 100     56 if (($class ne 'RPC::XML::Function') &&
      66        
174             (! ((exists $new_proc->{signature}) &&
175             (ref($new_proc->{signature}) eq 'ARRAY') &&
176             scalar(@{$new_proc->{signature}}))))
177             {
178 1         4 return "${class}::new: Missing required data (signatures)";
179             }
180 9         18 bless $new_proc, $class;
181              
182             # This needs to happen post-bless in case of error (for error messages)
183 9         23 return $new_proc->make_sig_table;
184             }
185              
186             ###############################################################################
187             #
188             # Sub Name: make_sig_table
189             #
190             # Description: Create a hash table of the signatures that maps to the
191             # corresponding return type for that particular invocation.
192             # Makes looking up call patterns much easier.
193             #
194             # Arguments: NAME IN/OUT TYPE DESCRIPTION
195             # $self in ref Object of this class
196             #
197             # Globals: %VALID_TYPES
198             #
199             # Returns: Success: $self
200             # Failure: error message
201             #
202             ###############################################################################
203             sub make_sig_table
204             {
205 12     12 0 13 my $self = shift;
206              
207 12         12 my ($return, $rest, @rest);
208 12         18 my $me = ref($self) . '::make_sig_table';
209              
210 12         27 delete $self->{sig_table};
211 12         11 for my $sig (@{$self->{signature}})
  12         21  
212             {
213 20         40 ($return, @rest) = split / /, $sig;
214 20 100       31 if (! $return)
215             {
216 1         5 return "$me: Invalid signature, cannot be null";
217             }
218 19 100       36 if (! $VALID_TYPES{$return})
219             {
220 1         5 return "$me: Unknown return type '$return'";
221             }
222             # Not going to add List::MoreUtils to my dependencies list, so suppress
223             # this critic flag:
224             ## no critic (ProhibitBooleanGrep)
225 18 100       19 if (grep { ! $VALID_TYPES{$_} } @rest)
  17         36  
226             {
227 1         5 return "$me: One or more invalid types in signature";
228             }
229              
230 17         20 $rest = join q{ } => @rest;
231             # If the key $rest already exists, then this is a collision
232 17 100       33 if ($self->{sig_table}->{$rest})
233             {
234             return
235 2         16 "$me: Cannot have two different return values for one set " .
236             "of params ($return vs. $self->{sig_table}->{$rest})";
237             }
238              
239 15         24 $self->{sig_table}->{$rest} = $return;
240             }
241              
242 7         27 return $self;
243             }
244              
245             # These are basic accessor/setting functions for the various attributes
246              
247 4     4 1 565 sub name { return shift->{name}; } # "name" cannot be changed at this level
248 3   50 3 1 21 sub namespace { return shift->{namespace} || q{}; } # Nor can "namespace"
249              
250             sub help
251             {
252 3     3 1 6 my ($self, $value) = @_;
253              
254 3 100       5 if ($value)
255             {
256 1         1 $self->{help} = $value;
257             }
258              
259 3         9 return $self->{help};
260             }
261              
262             sub version
263             {
264 3     3 1 4 my ($self, $value) = @_;
265              
266 3 100       7 if ($value)
267             {
268 1         3 $self->{version} = $value;
269             }
270              
271 3         7 return $self->{version};
272             }
273              
274             sub hidden
275             {
276 4     4 1 197 my ($self, $value) = @_;
277              
278 4 100       11 if ($value)
279             {
280 1         2 $self->{hidden} = $value;
281             }
282              
283 4         10 return $self->{hidden};
284             }
285              
286             sub code
287             {
288 6     6 1 8 my ($self, $value) = @_;
289              
290 6 100 100     17 if ($value and ref $value eq 'CODE')
291             {
292 1         2 $self->{code} = $value;
293             }
294              
295 6         16 return $self->{code};
296             }
297              
298             sub signature
299             {
300 10     10 1 293 my ($self, $sig) = @_;
301              
302 10 100       14 if ($sig)
303             {
304 3 100       9 if (ref $sig eq 'ARRAY')
305             {
306 2         4 my $old = $self->{signature};
307 2         2 $self->{signature} = $sig;
308 2         5 my $is_good = $self->make_sig_table;
309 2 100       7 if (! ref $is_good)
310             {
311             # If it failed to re-init the table, restore the old list (and
312             # old table). We don't have to check this return, since it had
313             # worked before.
314 1         1 $self->{signature} = $old;
315 1         3 $self->make_sig_table;
316              
317             # Return an error message, since this failed:
318 1         4 return ref($self) . "::signature: $is_good";
319             }
320             }
321             else
322             {
323             # Anything not an array ref isn't useful
324 1         4 return ref($self) . "::signature: Bad value '$sig'";
325             }
326             }
327              
328             # Return a copy of the array, not the original
329 8         5 return [ @{$self->{signature}} ];
  8         30  
330             }
331              
332             ###############################################################################
333             #
334             # Sub Name: clone
335             #
336             # Description: Create a near-exact copy of the invoking object, save that
337             # the listref in the "signature" key is a copy, not a ref
338             # to the same list.
339             #
340             # Arguments: NAME IN/OUT TYPE DESCRIPTION
341             # $self in ref Object of this class
342             #
343             # Returns: Success: $new_self
344             # Failure: error message
345             #
346             ###############################################################################
347             sub clone
348             {
349 0     0 1 0 my $self = shift;
350              
351 0         0 my $new_self = {};
352 0         0 for (keys %{$self})
  0         0  
353             {
354 0 0       0 next if $_ eq 'signature';
355 0         0 $new_self->{$_} = $self->{$_};
356             }
357 0 0       0 if (! $self->isa('RPC::XML::Function'))
358             {
359 0         0 $new_self->{signature} = [ @{$self->{signature}} ];
  0         0  
360             }
361              
362 0         0 return bless $new_self, ref $self;
363             }
364              
365             ###############################################################################
366             #
367             # Sub Name: add_signature
368             # delete_signature
369             #
370             # Description: This pair of functions may be used to add and remove
371             # signatures from a method-object.
372             #
373             # Arguments: NAME IN/OUT TYPE DESCRIPTION
374             # $self in ref Object of this class
375             # @args in list One or more signatures
376             #
377             # Returns: Success: $self
378             # Failure: error string
379             #
380             ###############################################################################
381             sub add_signature
382             {
383 0     0 1 0 my ($self, @args) = @_;
384              
385 0         0 my (%sigs, $is_good, $old);
386              
387             # Preserve the original in case adding the new one causes a problem
388 0         0 $old = $self->{signature};
389 0         0 %sigs = map { $_ => 1 } @{$self->{signature}};
  0         0  
  0         0  
390 0         0 for my $one_sig (@args)
391             {
392 0 0       0 my $sig_key = (ref $one_sig) ? join q{ } => @{$one_sig} : $one_sig;
  0         0  
393 0         0 $sigs{$sig_key} = 1;
394             }
395 0         0 $self->{signature} = [ keys %sigs ];
396 0         0 $is_good = $self->make_sig_table;
397 0 0       0 if (! ref $is_good)
398             {
399             # Because this failed, we have to restore the old table and return
400             # an error
401 0         0 $self->{signature} = $old;
402 0         0 $self->make_sig_table;
403 0         0 return ref($self) . '::add_signature: Error re-hashing table: ' .
404             $is_good;
405             }
406              
407 0         0 return $self;
408             }
409              
410             sub delete_signature
411             {
412 0     0 1 0 my ($self, @args) = @_;
413              
414 0         0 my %sigs;
415              
416 0         0 my $old = $self->{signature};
417 0         0 %sigs = map { $_ => 1 } @{$self->{signature}};
  0         0  
  0         0  
418 0         0 for my $one_sig (@args)
419             {
420 0 0       0 my $sig_key = (ref $one_sig) ? join q{ } => @{$one_sig} : $one_sig;
  0         0  
421 0         0 delete $sigs{$sig_key};
422             }
423 0         0 $self->{signature} = [ keys %sigs ];
424              
425 0 0       0 if (@{$self->{signature}} == 0)
  0         0  
426             {
427             # Don't have to re-run make_sig_table, because it's still valid for
428             # this set:
429 0         0 $self->{signature} = $old;
430 0         0 return ref($self) . '::delete_signature: Cannot delete last signature';
431             }
432              
433             # This can't fail, because deleting a signature will never cause an
434             # ambiguity in the table like adding one could.
435 0         0 return $self->make_sig_table;
436             }
437              
438             ###############################################################################
439             #
440             # Sub Name: match_signature
441             #
442             # Description: Determine if the passed-in signature string matches any
443             # of this method's known signatures.
444             #
445             # Arguments: NAME IN/OUT TYPE DESCRIPTION
446             # $self in ref Object of this class
447             # $sig in scalar Signature to check for
448             #
449             # Returns: Success: return type as a string
450             # Failure: 0
451             #
452             ###############################################################################
453             sub match_signature
454             {
455 0     0 1 0 my $self = shift;
456 0         0 my $sig = shift;
457              
458 0 0       0 if (ref $sig)
459             {
460 0         0 $sig = join q{ } => @{$sig};
  0         0  
461             }
462              
463 0   0     0 return $self->{sig_table}->{$sig} || 0;
464             }
465              
466             ###############################################################################
467             #
468             # Sub Name: reload
469             #
470             # Description: Reload the method's code and ancillary data from the file
471             #
472             # Arguments: NAME IN/OUT TYPE DESCRIPTION
473             # $self in ref Object of this class
474             #
475             # Returns: Success: $self
476             # Failure: error message
477             #
478             ###############################################################################
479             sub reload
480             {
481 1     1 1 242 my $self = shift;
482              
483 1         2 my $class = ref $self;
484 1         3 my $me = "${class}::reload";
485              
486 1 50       4 if (! $self->{file})
487             {
488 1         4 return "$me: No file associated with method $self->{name}";
489             }
490              
491 0         0 my ($newly_loaded) = load_xpl_file($self->{file});
492              
493 0 0       0 if (ref $newly_loaded)
494             {
495             # Update the information on this actual object
496 0         0 for (keys %{$newly_loaded})
  0         0  
497             {
498 0         0 $self->{$_} = $newly_loaded->{$_};
499             }
500             # Re-calculate the signature table, in case that changed as well
501 0         0 return $self->make_sig_table;
502             }
503             else
504             {
505 0         0 return "$me: Error loading $self->{file}: $newly_loaded";
506             }
507             }
508              
509             ###############################################################################
510             #
511             # Sub Name: load_xpl_file
512             #
513             # Description: Load a XML-encoded method description (generally denoted
514             # by a *.xpl suffix) and return the relevant information.
515             #
516             # Note that this is not a method, it does not take $self as
517             # an argument.
518             #
519             # Arguments: NAME IN/OUT TYPE DESCRIPTION
520             # $file in scalar File to load
521             #
522             # Returns: Success: hashref of values
523             # Failure: error string
524             #
525             ###############################################################################
526             sub load_xpl_file
527             {
528 4     4 0 7 my $file = shift;
529              
530 4         1150 require XML::Parser;
531              
532 0           my ($me, $new_proc, $signature, $code, $codetext, $accum, $P, $fh,
533             $eval_ret, $class, %attr);
534              
535 0           $me = __PACKAGE__ . '::load_xpl_file';
536              
537 0           $new_proc = {};
538             # So these don't end up undef, since they're optional elements
539 0           $new_proc->{hidden} = 0;
540 0           $new_proc->{version} = q{};
541 0           $new_proc->{help} = q{};
542 0           $new_proc->{namespace} = __PACKAGE__;
543             $P = XML::Parser->new(
544             ErrorContext => 1,
545             Handlers => {
546 0     0     Char => sub { $accum .= $_[1] },
547 0     0     Start => sub { %attr = splice @_, 2 },
548             End => sub {
549 0     0     my $elem = $_[1];
550              
551 0           $accum =~ s/^\s+//;
552 0           $accum =~ s/\s+$//;
553 0 0         if ($elem eq 'signature')
    0          
    0          
    0          
554             {
555 0   0       $new_proc->{signature} ||= [];
556 0           push @{$new_proc->{signature}}, $accum;
  0            
557             }
558             elsif ($elem eq 'hidden')
559             {
560 0           $new_proc->{hidden} = 1;
561             }
562             elsif ($elem eq 'code')
563             {
564 0 0 0       if (! ($attr{language} &&
565             $attr{language} ne 'perl'))
566             {
567 0           $new_proc->{$elem} = $accum;
568             }
569             }
570             elsif ('def' eq substr $elem, -3)
571             {
572 0           $class = 'RPC::XML::' . ucfirst substr $elem, 0, -3;
573             }
574             else
575             {
576 0           $new_proc->{$elem} = $accum;
577             }
578              
579 0           %attr = ();
580 0           $accum = q{};
581             }
582             }
583 0           );
584 0 0         if (! $P)
585             {
586 0           return "$me: Error creating XML::Parser object";
587             }
588 0 0         open $fh, '<', $file or return "$me: Error opening $file for reading: $!";
589             # Trap any errors
590 0           $eval_ret = eval { $P->parse($fh); 1; };
  0            
  0            
591 0 0         close $fh or return "$me: Error closing $file: $!";
592 0 0         if (! $eval_ret)
593             {
594 0           return "$me: Error parsing $file: $@";
595             }
596              
597             # Try to normalize $codetext before passing it to eval
598              
599             # Fudge a little and let them use '.' as a synonym for '::' in the
600             # namespace hierarchy.
601 0           $new_proc->{namespace} =~ s/[.]/::/g;
602              
603             # Next step is to munge away any actual subroutine name so that the eval
604             # yields an anonymous sub. Also insert the namespace declaration.
605 0           ($codetext = $new_proc->{code}) =~
606             s/sub\s+(?:[\w:]+)?\s*[{]/sub \{ package $new_proc->{namespace}; /;
607 0           $code = eval $codetext; ## no critic (ProhibitStringyEval)
608 0 0         return "$me: Error creating anonymous sub: $@" if $@;
609              
610 0           $new_proc->{code} = $code;
611             # Add the file's mtime for when we check for stat-based reloading, name
612             # for reloading, and init the "called" counter to 0.
613 0           $new_proc->{mtime} = (stat $file)[9];
614 0           $new_proc->{file} = $file;
615 0           $new_proc->{called} = 0;
616              
617 0           return ($new_proc, $class);
618             }
619              
620             ###############################################################################
621             #
622             # Sub Name: call
623             #
624             # Description: Encapsulates the invocation of the code block that the
625             # object is abstracting. Manages parameters, signature
626             # checking, etc.
627             #
628             # Arguments: NAME IN/OUT TYPE DESCRIPTION
629             # $self in ref Object of this class
630             # $srv in ref An object derived from the
631             # RPC::XML::Server class
632             # @params_in in list The params for the call itself
633             #
634             # Globals: None.
635             #
636             # Environment: None.
637             #
638             # Returns: Success: value
639             # Failure: RPC::XML::fault object
640             #
641             ###############################################################################
642             sub call
643             {
644 0     0 1   my ($self, $srv, @params_in) = @_;
645              
646 0           my (@paramtypes, @params, $signature, $resptype, $response, $name);
647              
648 0           $name = $self->name;
649             # Create the param list.
650             # The type for the response will be derived from the matching signature
651 0           @paramtypes = map { $_->type } @params_in;
  0            
652 0           @params = map { $_->value } @params_in;
  0            
653 0           $signature = join q{ } => @paramtypes;
654 0           $resptype = $self->match_signature($signature);
655             # Since there must be at least one signature with a return value (even
656             # if the param list is empty), this tells us if the signature matches:
657 0 0         if (! $resptype)
    0          
658             {
659 0           return $srv->server_fault(
660             badsignature =>
661             "method $name has no matching signature for the argument list: " .
662             "[$signature]"
663             );
664             }
665             elsif ($resptype eq 'dateTime.iso8601')
666             {
667 0           $resptype = 'datetime_iso8601';
668             }
669              
670             # Set these in case the server object is part of the param list
671 0           local $srv->{signature} = ## no critic (ProhibitLocalVars)
672             [ $resptype, @paramtypes ];
673 0           local $srv->{method_name} = $name; ## no critic (ProhibitLocalVars)
674             # For RPC::XML::Method (and derivatives), pass the server object
675 0 0         if ($self->isa('RPC::XML::Method'))
676             {
677 0           unshift @params, $srv;
678             }
679              
680             # Now take a deep breath and call the method with the arguments
681 0 0         if (! eval { $response = $self->{code}->(@params); 1; })
  0            
  0            
682             {
683             # On failure, propagate user-generated RPC::XML::fault exceptions, or
684             # transform Perl-level error/failure into such an object
685 0 0 0       if (blessed $@ and $@->isa('RPC::XML::fault'))
686             {
687 0           return $@;
688             }
689             else
690             {
691 0           return $srv->server_fault(
692             execerror => "Method $name returned error: $@"
693             );
694             }
695             }
696              
697             # Increment the 'called' key on the proc UNLESS the proc is named
698             # 'system.status' and has a boolean-true as the first param.
699 0 0 0       if (! (($name eq 'system.status') &&
      0        
      0        
700             @params_in &&
701             ($paramtypes[0] eq 'boolean') &&
702             $params[0]))
703             {
704 0           $self->{called}++;
705             }
706             # Create a suitable return value
707 0 0         if (! ref $response)
708             {
709 0 0         if ($resptype eq 'scalar')
710             {
711             # Server code from the RPC::XML::Function class doesn't use
712             # signatures, so if they didn't encode the returned value
713             # themselves they're trusting smart_encode() to get it right.
714 0           $response = smart_encode($response);
715             }
716             else
717             {
718             # We checked that this was valid earlier, so no need for further
719             # tests here.
720 0           $response = "RPC::XML::$resptype"->new($response);
721             }
722             }
723              
724 0           return $response;
725             }
726              
727             ###############################################################################
728             #
729             # Description: This is now an empty sub-class of RPC::XML::Procedure.
730             # It differs behaviorally from ::Procedure in that the
731             # RPC::XML::Server object is passed in the arguments list
732             # when the underlying code is invoked by call().
733             #
734             # Functions: None.
735             #
736             ###############################################################################
737              
738             package RPC::XML::Method;
739              
740 10     10   57 use strict;
  10         18  
  10         268  
741 10     10   40 use warnings;
  10         12  
  10         262  
742 10     10   33 use vars qw(@ISA);
  10         9  
  10         486  
743              
744             @ISA = qw(RPC::XML::Procedure);
745              
746             ###############################################################################
747             #
748             # Description: This is a type of Procedure that does no signature tests
749             # at either creation or invocation. Like RPC::XML::Procedure
750             # it does *not* get the RPC::XML::Server object when the
751             # underlying code is invoked by call().
752             #
753             # Functions: signature
754             # make_sig_table (called by some superclass methods)
755             # add_signature
756             # delete_signature
757             # match_signature
758             #
759             ###############################################################################
760              
761             package RPC::XML::Function;
762              
763 10     10   37 use strict;
  10         10  
  10         198  
764 10     10   29 use warnings;
  10         15  
  10         182  
765 10     10   32 use vars qw(@ISA);
  10         14  
  10         297  
766 10         48 use subs qw(
767             signature make_sig_table add_signature delete_signature match_signature
768 10     10   33 );
  10         10  
769              
770             @ISA = qw(RPC::XML::Procedure);
771              
772             # These are the bits that have to be different for RPC::XML::Function versus
773             # the other procedure types. They are simple-enough that they don't need
774             # dedicated comment-blocks for them.
775 0     0     sub signature { return [ 'scalar' ]; }
776 0     0     sub make_sig_table { return shift; }
777 0     0     sub add_signature { return shift; }
778 0     0     sub delete_signature { return shift; }
779 0     0     sub match_signature { return 'scalar'; }
780              
781             1;
782              
783             __END__