/[cvs]/joko/Scripts/psh/lib/RPC/XML/Client.pm
ViewVC logotype

Annotation of /joko/Scripts/psh/lib/RPC/XML/Client.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations)
Fri Jun 14 21:22:11 2002 UTC (22 years, 3 months ago) by cvsjoko
Branch point for: nfo, MAIN
Initial revision

1 cvsjoko 1.1 ###############################################################################
2     #
3     # This file copyright (c) 2001 by Randy J. Ray <rjray@blackperl.com>,
4     # all rights reserved
5     #
6     # Copying and distribution are permitted under the terms of the Artistic
7     # License as distributed with Perl versions 5.002 and later. See
8     # http://language.perl.com/misc/Artistic.html
9     #
10     ###############################################################################
11     #
12     # $Id: Client.pm,v 1.6 2002/01/27 23:16:13 rjray Exp $
13     #
14     # Description: This class implements an RPC::XML client, using LWP to
15     # manage the underlying communication protocols. It relies
16     # on the RPC::XML transaction core for data management.
17     #
18     # Functions: new
19     # send_request
20     # simple_request
21     # uri
22     # useragent
23     # request
24     #
25     # Libraries: LWP::UserAgent
26     # HTTP::Request
27     # URI
28     # RPC::XML
29     #
30     # Global Consts: $VERSION
31     #
32     ###############################################################################
33    
34     package RPC::XML::Client;
35    
36     use 5.005;
37     use strict;
38     use vars qw($VERSION);
39     use subs qw(new simple_request send_request uri useragent request
40     fault_handler error_handler combined_handler);
41    
42     require LWP::UserAgent;
43     require HTTP::Request;
44     require URI;
45    
46     require RPC::XML;
47     require RPC::XML::Parser;
48    
49     $VERSION = do { my @r=(q$Revision: 1.6 $=~/\d+/g); sprintf "%d."."%02d"x$#r,@r };
50    
51     1;
52    
53     ###############################################################################
54     #
55     # Sub Name: new
56     #
57     # Description: Create a LWP::UA instance and add some extra material
58     # specific to our purposes.
59     #
60     # Arguments: NAME IN/OUT TYPE DESCRIPTION
61     # $class in scalar Class to bless into
62     # $location in scalar URI path for requests to go to
63     # %attrs in hash Extra info
64     #
65     # Globals: $VERSION
66     #
67     # Returns: Success: object reference
68     # Failure: error string
69     #
70     ###############################################################################
71     sub new
72     {
73     my $class = shift;
74     my $location = shift;
75     my %attrs = @_;
76    
77     $class = ref($class) || $class;
78     return "${class}::new: Missing location argument" unless $location;
79    
80     my ($self, $UA, $REQ, $PARSER);
81    
82     # Start by getting the LWP::UA object
83     $UA = LWP::UserAgent->new() or
84     return "${class}::new: Unable to get LWP::UserAgent object";
85     $UA->agent(sprintf("%s/%s %s", $class, $VERSION, $UA->agent));
86     $self->{__useragent} = $UA;
87    
88     # Next get the request object for later use
89     $REQ = HTTP::Request->new(POST => $location) or
90     return "${class}::new: Unable to get HTTP::Request object";
91     $self->{__request} = $REQ;
92     $REQ->header(Content_Type => 'text/xml');
93    
94     # Note and preserve any error or fault handlers. Check the combo-handler
95     # first, as it is superceded by anything more specific.
96     if (ref $attrs{combined_handler})
97     {
98     $self->{__error_cb} = $attrs{combined_handler};
99     $self->{__fault_cb} = $attrs{combined_handler};
100     delete $attrs{combined_handler};
101     }
102     if (ref $attrs{fault_handler})
103     {
104     $self->{__fault_cb} = $attrs{fault_handler};
105     delete $attrs{fault_handler};
106     }
107     if (ref $attrs{error_handler})
108     {
109     $self->{__error_cb} = $attrs{error_handler};
110     delete $attrs{error_handler};
111     }
112    
113     # Preserve any remaining attributes passed in
114     $self->{$_} = $attrs{$_} for (keys %attrs);
115    
116     # Then, get the RPC::XML::Parser instance
117     $PARSER = RPC::XML::Parser->new() or
118     return "${class}::new: Unable to get RPC::XML::Parser object";
119     $self->{__parser} = $PARSER;
120    
121     bless $self, $class;
122     }
123    
124     ###############################################################################
125     #
126     # Sub Name: simple_request
127     #
128     # Description: Simplify the request process by both allowing for direct
129     # data on the incoming side, and for returning a native
130     # value rather than an object reference.
131     #
132     # Arguments: NAME IN/OUT TYPE DESCRIPTION
133     # $self in ref Class instance
134     # @args in list Various args -- see comments
135     #
136     # Globals: $RPC::XML::ERROR
137     #
138     # Returns: Success: value
139     # Failure: undef, error in $RPC::XML::ERROR
140     #
141     ###############################################################################
142     sub simple_request
143     {
144     my ($self, @args) = @_;
145    
146     my ($return, $value);
147    
148     $RPC::XML::ERROR = '';
149    
150     $return = $self->send_request(@args);
151     unless (ref $return)
152     {
153     $RPC::XML::ERROR = ref($self) . "::simple_request: $return";
154     return undef;
155     }
156     $return->value;
157     }
158    
159     ###############################################################################
160     #
161     # Sub Name: send_request
162     #
163     # Description: Take a RPC::XML::request object, dispatch a request, and
164     # parse the response. The return value should be a
165     # RPC::XML::response object, or an error string.
166     #
167     # Arguments: NAME IN/OUT TYPE DESCRIPTION
168     # $self in ref Class instance
169     # $req in ref RPC::XML::request object
170     #
171     # Returns: Success: RPC::XML::response object instance
172     # Failure: error string
173     #
174     ###############################################################################
175     sub send_request
176     {
177     my ($self, $req, @args) = @_;
178    
179     my ($me, $message, $response, $reqclone, $value);
180    
181     $me = ref($self) . ':send_request';
182    
183     if (! UNIVERSAL::isa($req, 'RPC::XML::request'))
184     {
185     # Assume that $req is the name of the routine to be called
186     $req = RPC::XML::request->new($req, @args);
187     return "$me: Error creating RPC::XML::request object: $RPC::XML::ERROR"
188     unless ($req); # $RPC::XML::ERROR is already set
189     }
190    
191     ($reqclone = $self->{__request}->clone)->content($req->as_string);
192     $reqclone->header(Host => URI->new($reqclone->uri)->host);
193     $response = $self->{__useragent}->request($reqclone);
194    
195     unless ($response->is_success)
196     {
197     $message = "$me: HTTP server error: " . $response->message;
198     return (ref($self->{__error_cb}) eq 'CODE') ?
199     $self->{__error_cb}->($message) : $message;
200     }
201    
202     # The return value from the parser's parse method no longer works as a
203     # direct return value for us
204     $value = $self->{__parser}->parse($response->content);
205    
206     # Rather, we now have to check if there is a callback in the case of
207     # errors or faults
208     if (! ref($value))
209     {
210     $message = "$me: parse-level error: $value";
211     return (ref($self->{__error_cb}) eq 'CODE') ?
212     $self->{__error_cb}->($message) : $message;
213     }
214     elsif ($value->is_fault)
215     {
216     return (ref($self->{__fault_cb}) eq 'CODE') ?
217     $self->{__fault_cb}->($value->value) : $value->value;
218     }
219    
220     $value->value;
221     }
222    
223     ###############################################################################
224     #
225     # Sub Name: uri
226     #
227     # Description: Get or set the URI portion of the request
228     #
229     # Arguments: NAME IN/OUT TYPE DESCRIPTION
230     # $self in ref Object of this class
231     # $uri in scalar New URI, if passed
232     #
233     # Returns: Current URI, undef if trying to set an invalid URI
234     #
235     ###############################################################################
236     sub uri
237     {
238     $_[0]->{__request}->uri($_[1]);
239     }
240    
241     # Accessor methods for the LWP::UserAgent and HTTP::Request objects
242     sub useragent { $_[0]->{__useragent} }
243     sub request { $_[0]->{__request} }
244    
245     # These are get/set accessors for the fault-handler, error-handler and the
246     # combined fault/error handler.
247     sub fault_handler
248     {
249     my ($self, $newval) = @_;
250    
251     my $val = $self->{__fault_cb};
252     $self->{__fault_cb} = $newval if ($newval and ref($newval));
253     # Special: an explicit undef is used to clear the callback
254     $self->{__fault_cb} = undef if (@_ == 2 and (! defined $newval));
255    
256     $val;
257     }
258     sub error_handler
259     {
260     my ($self, $newval) = @_;
261    
262     my $val = $self->{__error_cb};
263     $self->{__error_cb} = $newval if ($newval and ref($newval));
264     # Special: an explicit undef is used to clear the callback
265     $self->{__error_cb} = undef if (@_ == 2 and (! defined $newval));
266    
267     $val;
268     }
269     sub combined_handler
270     {
271     my ($self, $newval) = @_;
272    
273     ($self->fault_handler($newval), $self->error_handler($newval));
274     }
275    
276     __END__
277    
278     =pod
279    
280     =head1 NAME
281    
282     RPC::XML::Client - An XML-RPC client class
283    
284     =head1 SYNOPSIS
285    
286     require RPC::XML;
287     require RPC::XML::Client;
288    
289     $cli = RPC::XML::Client->new('http://www.localhost.net/RPCSERV');
290     $resp = $cli->send_request('system.listMethods');
291    
292     print (ref $resp) ? join(', ', @{$resp->value}) : "Error: $resp";
293    
294     =head1 DESCRIPTION
295    
296     This is an XML-RPC client built upon the B<RPC::XML> data classes, and using
297     B<LWP::UserAgent> and B<HTTP::Request> for the communication layer. This
298     client supports the full XML-RPC specification.
299    
300     =head1 METHODS
301    
302     The following methods are available:
303    
304     =over 4
305    
306     =item new (URI [, ARGS])
307    
308     Creates a new client object that will route its requests to the URL provided.
309     The constructor creates a B<HTTP::Request> object and a B<LWP::UserAgent>
310     object, which are stored on the client object. When requests are made, these
311     objects are ready to go, with the headers set appropriately. The return value
312     of this method is a reference to the new object. The C<URI> argument may be a
313     string or an object from the B<URI> class from CPAN.
314    
315     Any additional arguments are treated as key-value pairs. Most are attached to
316     the object itself without change. The following are recognized by C<new> and
317     treated specially:
318    
319     =over 8
320    
321     =item error_handler
322    
323     If passed, the value must be a code reference that will be invoked when a
324     request results in a transport-level error. The closure will receive a
325     single argument, the text of the error message from the failed communication
326     attempt. It is expected to return a single value (assuming it returns at all).
327    
328     =item fault_handler
329    
330     If passed, the value must be a code reference. This one is invoked when a
331     request results in a fault response from the server. The closure will receive
332     a single argument, a B<RPC::XML::fault> instance that can be used to retrieve
333     the code and text-string of the fault. It is expected to return a single
334     value (if it returns at all).
335    
336     =item combined_handler
337    
338     If this parameter is specified, it too must have a code reference as a value.
339     It is installed as the handler for both faults and errors. Should either of
340     the other parameters be passed in addition to this one, they will take
341     precedence over this (more-specific wins out over less). As a combined
342     handler, the closure will get a string (non-reference) in cases of errors, and
343     an instance of B<RPC::XML::fault> in cases of faults. This allows the
344     developer to install a simple default handler, while later providing a more
345     specific one by means of the methods listed below.
346    
347     =back
348    
349     See the section on the effects of callbacks on return values, below.
350    
351     =item uri ([URI])
352    
353     Returns the B<URI> that the invoking object is set to communicate with for
354     requests. If a string or C<URI> class object is passed as an argument, then
355     the URI is set to the new value. In either case, the pre-existing value is
356     returned.
357    
358     =item useragent
359    
360     Returns the B<LWP::UserAgent> object instance stored on the client object.
361     It is not possible to assign a new such object, though direct access to it
362     should allow for any header modifications or other needed operations.
363    
364     =item request
365    
366     Returns the B<HTTP::Request> object. As with the above, it is not allowed to
367     assign a new object, but access to this value should allow for any needed
368     operations.
369    
370     =item simple_request (ARGS)
371    
372     This is a somewhat friendlier wrapper around the next routine (C<send_request>)
373     that returns Perl-level data rather than an object reference. The arguments may
374     be the same as one would pass to the B<RPC::XML::request> constructor, or there
375     may be a single request object as an argument. The return value will be a
376     native Perl value. If the return value is C<undef>, an error has occurred and
377     C<simple_request> has placed the error message in the global variable
378     C<B<$RPC::XML::ERROR>>.
379    
380     =item send_request (ARGS)
381    
382     Sends a request to the server and attempts to parse the returned data. The
383     argument may be an object of the B<RPC::XML::request> class, or it may be the
384     arguments to the constructor for the request class. The return value will be
385     either an error string or a data-type object. If the error encountered was a
386     run-time error within the RPC request itself, then the call will return a
387     C<RPC::XML::fault> value rather than an error string.
388    
389     If the return value from C<send_request> is not a reference, then it can only
390     mean an error on the client-side (a local problem with the arguments and/or
391     syntax, or a transport problem). All data-type classes now support a method
392     called C<is_fault> that may be easily used to determine if the "successful"
393     return value is actually a C<RPC::XML::fault> without the need to use
394     C<UNIVERSAL::ISA>.
395    
396     =item error_handler([CODEREF])
397    
398     =item fault_handler([CODEREF])
399    
400     =item combined_handler([CODEREF])
401    
402     These accessor methods get (and possibly set, if CODEREF is passed) the
403     specified callback/handler. The return value is always the current handler,
404     even when setting a new one (allowing for later restoration, if desired).
405    
406     =back
407    
408     =head2 Callbacks and Return Values
409    
410     If a callback is installed for errors or faults, it will be called before
411     either of C<send_request> or C<simple_request> return. If the callback calls
412     B<die> or otherwise interrupts execution, then there is no need to worry about
413     the effect on return values. Otherwise, the return value of the callback
414     becomes the return value of the original method (C<send_request> or
415     C<simple_request>). Thus, all callbacks are expected, if they return at all,
416     to return exactly one value. It is recommended that any callback return values
417     conform to the expected return values. That is, an error callback would
418     return a string, a fault callback would return the fault object.
419    
420     =head1 DIAGNOSTICS
421    
422     All methods return some type of reference on success, or an error string on
423     failure. Non-reference return values should always be interpreted as errors,
424     except in the case of C<simple_request>.
425    
426     =head1 CAVEATS
427    
428     This began as a reference implementation in which clarity of process and
429     readability of the code took precedence over general efficiency. It is now
430     being maintained as production code, but may still have parts that could be
431     written more efficiently.
432    
433     =head1 CREDITS
434    
435     The B<XML-RPC> standard is Copyright (c) 1998-2001, UserLand Software, Inc.
436     See <http://www.xmlrpc.com> for more information about the B<XML-RPC>
437     specification.
438    
439     =head1 LICENSE
440    
441     This module is licensed under the terms of the Artistic License that covers
442     Perl. See <http://language.perl.com/misc/Artistic.html> for the license
443     itself.
444    
445     =head1 SEE ALSO
446    
447     L<RPC::XML>, L<RPC::XML::Server>
448    
449     =head1 AUTHOR
450    
451     Randy J. Ray <rjray@blackperl.com>
452    
453     =cut

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed