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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Fri Jun 14 21:22:11 2002 UTC (22 years, 3 months ago) by cvsjoko
Branch: nfo, MAIN
CVS Tags: r001, HEAD
Changes since 1.1: +0 -0 lines
first import

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