/[cvs]/nfo/php/libs/org.netfrag.glib/DataSource/Proxy/XMLRPC.php
ViewVC logotype

Contents of /nfo/php/libs/org.netfrag.glib/DataSource/Proxy/XMLRPC.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.8 - (show annotations)
Wed Jun 16 15:36:19 2004 UTC (20 years, 2 months ago) by joko
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +6 -1 lines
changed semantics to call Data::Encode

1 <?
2 /**
3 * This file contains the DataSource::Proxy::XMLRPC module.
4 *
5 * @author Andreas Motl <andreas.motl@ilo.de>
6 * @package org.netfrag.glib
7 * @name DataSource::Proxy::XMLRPC
8 *
9 */
10
11
12 /*
13 ## --------------------------------------------------------------------------
14 ## $Id: XMLRPC.php,v 1.7 2003/04/18 15:42:26 joko Exp $
15 ## --------------------------------------------------------------------------
16 ## $Log: XMLRPC.php,v $
17 ## Revision 1.7 2003/04/18 15:42:26 joko
18 ## minor update to comment
19 ##
20 ## Revision 1.6 2003/04/04 21:23:29 joko
21 ## session-based rpc-communcation: revamped code (especially 'function _call')
22 ## renamed state-handling trigger-methods: now _sleep and _wakeup
23 ##
24 ## Revision 1.5 2003/03/28 06:56:52 joko
25 ## updated logging/debugging code
26 ##
27 ## Revision 1.4 2003/03/28 03:00:12 joko
28 ## enhanced error- and exception-handling
29 ##
30 ## Revision 1.3 2003/03/27 16:05:01 joko
31 ## enhanced 'function _call': debugging, tracing and autodisconnect now parametrized
32 ##
33 ## Revision 1.2 2003/03/05 23:16:48 joko
34 ## updated docu - phpDocumentor is very strict about its 'blocks'...
35 ##
36 ## Revision 1.1 2003/03/03 21:53:52 joko
37 ## refactored from Data::Driver::RPC::Remote
38 ##
39 ## Revision 1.4 2003/02/20 21:42:43 joko
40 ## + fix: always converting from utf8 into latin here (for now)
41 ##
42 ## Revision 1.3 2003/02/13 21:51:29 joko
43 ## + now can remember its connection-state
44 ## + sub ping
45 ##
46 ## Revision 1.2 2003/02/13 00:42:44 joko
47 ## +- renamed modules
48 ##
49 ## Revision 1.1 2003/02/09 17:25:38 joko
50 ## + refactored from flib/Application/RPC/Remote.php
51 ##
52 ## Revision 1.6 2003/02/03 03:37:45 jonen
53 ## - removed unused argument '$decode' at function '_call()'
54 ## + added argument '$options=array()' at function '_call()'
55 ## which will be passed to function '&decodeData()' for e.g. utf8 decoding
56 ## + added '$encoder->toISO()' at '&decodeData()', (re)moved from 'ProxyObject.php'
57 ##
58 ## Revision 1.5 2002/12/22 13:24:09 jonen
59 ## + added utf8 encoding at 'send()' toggled by option
60 ##
61 ## Revision 1.4 2002/12/19 02:02:25 jonen
62 ## + minor changes
63 ##
64 ## Revision 1.3 2002/12/19 01:59:37 jonen
65 ## + minor changes: coment debug prints
66 ##
67 ## Revision 1.2 2002/12/05 21:45:31 joko
68 ## + debugging
69 ##
70 ## Revision 1.1 2002/12/01 17:23:58 joko
71 ## + initial check-in
72 ##
73 ## Revision 1.3 2002/12/01 06:22:57 cvsjoko
74 ## + minor update: now can use config defaults or given args
75 ##
76 ## Revision 1.2 2002/10/29 19:14:45 cvsjoko
77 ## - bugfix: dont' do utf8-encoding here
78 ##
79 ## Revision 1.1 2002/10/09 00:51:39 cvsjoko
80 ## + new
81 ##
82 ##
83 ## -------------------------------------------------------------------------
84 */
85
86
87 // V1: normal require
88 //require_once 'XML/RPC/RPC.php';
89
90 // V2: first time load of foreign module (PEAR::XML::RPC)
91 //require_once 'XML/RPC/RPC.php';
92 loadModule('XML::RPC::RPC');
93
94 loadModule('Class::Logger');
95
96
97 /**
98 * This is the DataSource::Proxy::XMLRPC module.
99 *
100 * @author Andreas Motl <andreas.motl@ilo.de>
101 * @package org.netfrag.glib
102 * @subpackage DataSource
103 * @name DataSource::Proxy::XMLRPC
104 *
105 * @todo SOAP?
106 *
107 */
108 class DataSource_Proxy_XMLRPC extends Class_Logger {
109
110 var $configured;
111 var $meta = array();
112 var $response = null;
113 var $errors = array();
114
115 function DataSource_Proxy_XMLRPC($args = array()) {
116
117 parent::constructor();
118
119 //print Dumper($this, $args);
120 //print Dumper($args);
121
122 $this->_wakeup();
123
124 // force connect?
125
126 // V1
127 /*
128 if (!isset($this->meta[connected]) || $args[connect]) {
129 $this->meta[connected] = 1;
130 }
131 */
132
133 // V2
134 $this->FORCE_CONNECT = $args[connect];
135
136
137
138 // merge args - V1
139 //if ($args['Host']) { $this->HOST = $args['Host']; }
140 //if ($args['Port']) { $this->PORT = $args['Port']; }
141
142 // merge args - V2
143 // TODO: php::merge_to($this, $args);
144 //php::merge_to($this, $args);
145 //print Dumper($args);
146 if (is_array($args)) {
147 foreach ($args as $key => $val) {
148 //print "key: $key<br/>";
149 $key = strtoupper($key);
150 $this->$key = $val;
151 }
152 }
153
154 // check if host is valid
155 if (!$this->HOST) {
156 $this->_raiseException( "->constructor: attribute 'host' is empty, please check your settings");
157 return;
158 }
159
160 if (!$this->PORT) {
161 $this->_raiseException( "->constructor: attribute 'port' is empty, please check your settings");
162 return;
163 }
164
165 $this->configured = 1;
166
167 }
168
169 function _wakeup() {
170 global $Data_Driver_RPC_Remote_meta;
171 session_register_safe("Data_Driver_RPC_Remote_meta");
172 $this->meta = $Data_Driver_RPC_Remote_meta;
173 $this->_sleep();
174 }
175
176 function _sleep() {
177 global $Data_Driver_RPC_Remote_meta;
178 $Data_Driver_RPC_Remote_meta = $this->meta;
179 }
180
181 function send($command, $data = "", $options = array()) {
182
183 $this->log(get_class($this) . "->send: " . $command, PEAR_LOG_DEBUG);
184
185 /*
186 if (!$this->isConnected()) {
187 $this->_raiseException( "->send[ command=$command ]: not connected while trying to send command!");
188 return;
189 }
190 */
191
192 // do 'encode' here and ...
193 if ($options[utf8]) {
194 $encoder = new Data_Encode($data);
195 $encoder->toUTF8();
196 $data = $encoder->get_result();
197 }
198 // call '_call' with 'decode'
199 return $this->_call($command, $data, $options);
200 }
201
202
203 function _call($command, $data = "", $options = array() ) {
204
205 $RETRY_COUNT = 0;
206 $RETRY_MAX = 1;
207
208 do {
209
210 $RETRY_COUNT++;
211
212 $this->__exception_method = '_call';
213
214 if (!$this->configured) {
215 $this->_raiseException("class not configured properly");
216 return;
217 }
218
219 // populate options list - mostly for debugging purposes
220 $options_list = array();
221 foreach ($options as $key => $value) {
222 array_push($options_list, "$key=$value");
223 }
224
225 $data_debug = $data;
226 if (is_array($data_debug)) { $data_debug = join(", ", $data_debug); }
227 $options_debug = join(", ", $options_list);
228 // FIXME: replace through '_raiseException'?
229 $this->log(get_class($this) . "->_call: " . $command . "(" . $data_debug . ") [" . $options_debug . "]", PEAR_LOG_DEBUG);
230
231 // trace
232 //print "call: $command<hr>";
233 //print Dumper($data);
234 //print Dumper($this);
235
236 // message - request
237 $msg = new XML_RPC_Message($command);
238
239 // data
240 if ($data) {
241 $data_enc = XML_RPC_encode($data);
242 $msg->addParam($data_enc);
243 }
244
245 $this->_hook_request($msg);
246
247 // ???
248 //print htmlentities($msg->serialize());
249
250 // remote procedure call
251 $rpc = new XML_RPC_Client("/", $this->HOST, $this->PORT);
252
253 // TODO: detect highlevel errors, raise proper exceptions on them (e.g. 'Unknown method', 'Method signature error(s)')
254 // done: now possible to declare tracing at this point in configuration
255 // Please look inside your {appname}/etc/hosts/{hostname}.php
256 $rpc->setDebug($this->TRACE);
257
258 //$rpc->setDebug(1);
259
260 if ( $this->response = $rpc->send($msg) ) {
261 // intermediate response checking
262 $errcode = $this->_hook_errorcheck();
263 $negotiation = $this->_hook_negotiation($errcode);
264 } else {
265 // TODO: redirect this error elsewhere!
266 //print "RPC-error!<br>";
267 $this->_raiseException("no response");
268 return;
269 }
270
271 // retry method issued right now - i.e. in case an authentication came in between
272 if (!$negotiation[retry]) {
273 break;
274 }
275
276 } while ($RETRY_COUNT < $RETRY_MAX);
277
278 // message - response
279 $response_enc = $this->response->value();
280
281 // TODO: what's this? prematurely returning here should not be considered "stable"....
282 $data = $this->decodeData($response_enc, $options);
283 $this->_hook_response($data);
284 return $data;
285
286 }
287
288
289 function &decodeData(&$payload, $options = array() ) {
290 //if (!is_object($payload)) { return; }
291 if ($payload) {
292 // data
293 $data = XML_RPC_decode($payload);
294 //print "data: " . dumpVar($response);
295
296 // decode UTF8 to ISO if wanted
297 //if ($options[to_latin]) {
298 $encoder = new Data_Encode($data);
299 $encoder->toISO();
300 $data = $encoder->get_result();
301 //}
302
303 $this->_be_connected();
304
305 return $data;
306 } else {
307 //print "ERROR!<br>";
308 return 0;
309 }
310 }
311
312 function _be_connected() {
313 $this->meta[connected] = 1;
314 $this->_sleep();
315 }
316
317 function _raiseException($message, $code = null) {
318
319 $classname = get_class($this);
320
321 if ($this->__exception_method) {
322 $message_full = $classname . '->' . $this->__exception_method . ': ' . $message;
323 }
324
325 // aggregate errors for this run/query
326 $this->_add_error($message, $code);
327
328 // spout out the error message of the raised exception
329 $this->log($classname . $message_full, PEAR_LOG_ERR);
330
331 // handle some stuff regarding more special behaviour (will this get rule-based sometimes?)
332
333 // handle 'FORCE_CONNECT'
334 $connect_condition = $this->FORCE_CONNECT = ($this->isConnected() && $this->DISCONNECT_ON_ERROR);
335 if ($connect_condition) {
336 $message = '->_raiseException: [DISCONNECT_ON_ERROR] done transparently. Please reconnect manually.';
337 $this->_add_error($classname . $message, $code);
338 //$this->log($classname . $message, PEAR_LOG_WARNING);
339 $this->log($classname . $message, PEAR_LOG_ERR);
340 $this->meta[connected] = 0;
341 $this->_sleep();
342 }
343 }
344
345 function isConnected() {
346 return $this->meta[connected];
347 }
348
349 function ping() {
350 $this->_call('ping');
351 }
352
353
354 function _hook_negotiation($error_code) {
355
356 $result = array();
357
358 // 401 = authorization required
359 if ($error_code == 401) {
360
361 //print "<b>401</b>!!!<br/>";
362 //print Dumper($this);
363
364 // V1 - authenticate using hardcoded plaintext values (bad thing inside here!!!)
365 $auth_ok = $this->_call('authenticate', array( user => 'hello', pass => '123' ));
366 //$auth_ok = $this->_call('authenticate', array( user => 'hello', pass => '12345' ));
367
368 // authentication success? try issued method again now...
369 if ($auth_ok) {
370 $result[retry] = 1;
371 }
372
373 // V2 - sub-negotiation:
374 // "Do we already have a password supplied in cache?"
375 // Use it if we have, otherwise redirect to login page
376 // prompting for credentials for specified transport.
377 //Header("Location: " . topicLink('Login'));
378 //print "user: " . $this->USER . "<br/>";
379 //print "pass: " . $this->PASS . "<br/>";
380
381 }
382
383 // 511 = sent unknown session identifier (probably: session timed out)
384 // solution: invalidate local session in state => new session will be attempted on next request
385 if ($error_code == 511) {
386 $this->meta[session][enabled] = 0;
387 $this->_sleep();
388 }
389
390 return $result;
391
392 }
393
394 function _hook_errorcheck() {
395 // Please look inside your {appname}/etc/hosts/{hostname}.php for toggling $this->DEBUG
396 if ($error_code = $this->response->faultCode()) {
397 // raise exception
398 //print "fault-code: " . $this->response->faultCode() . "<br/>";
399 //print "fault-string: " . $this->response->faultString() . "<br/>";
400 $this->_raiseException($this->response->faultString(), $error_code);
401 return $error_code;
402 }
403 }
404
405 //if ($this->DEBUG && $error_code = $msg_response->faultCode()) {
406
407 function _add_error($message, $code) {
408 array_push( $this->errors, array(code => $code, message => $message) );
409 }
410
411 function status() {
412 $status = array(
413 connected => $this->isConnected(),
414 errors => $this->errors,
415 );
416 $status[RPCSESSID] = $this->meta[session][id];
417 return $status;
418 }
419
420
421 // TODO: introduce condition: just do if connection requires session and/or auth
422 function _hook_request(&$request) {
423
424 //print Dumper($request);
425
426 // ignore core methods (like 'session_id') here to prevent recursive loops!
427 // would be a bad thing on the net!
428 if (in_array($request->methodname, array('ping', 'session_id'))) { return 1; }
429
430 // calculate conditions
431 $session_requested = 1;
432 //$use_session = $this->meta[session][requested];
433 $session_running = $this->meta[session][enabled];
434 $session_error = $this->meta[session][error];
435 $init_session = $session_requested && !$session_running && !$session_error;
436
437 // 1. if session already established, add sessionid to request and return
438 if ($session_running) {
439 //trace("Session " . $this->meta[session][id] . " already initialized!" . "<br/>");
440 // append additional parameter (hash with key 'RPCSESSID')
441 // to send assigned sessionid back to server inside each request
442 $data = array( RPCSESSID => $this->meta[session][id] );
443 $data_enc = XML_RPC_encode($data);
444 //print Dumper($data_enc);
445 $request->addParam($data_enc);
446 //return 1;
447 }
448
449
450 // 2. if session is required/requested, but not yet initialized,
451 // do it to be able to propagate the sessionid transparently later
452
453 if ($init_session) {
454 static $init_count;
455 $init_count++;
456 //trace("Initializing session: $init_count" . "<br/>");
457 //exit;
458 $response = $this->_call('session_id');
459 //print "response: " . Dumper($response) . "<br/>";
460 //exit;
461
462 if ($response) {
463 $this->meta[session][id] = $response;
464 $this->meta[session][enabled] = 1;
465 } else {
466 $this->meta[session][error] = 1;
467 }
468
469 $this->_sleep();
470 //print Dumper($this->meta);
471 //exit;
472 }
473
474 //print Dumper($request);
475
476 return 1;
477 }
478
479 function _hook_response(&$data) {
480 //$status[RPCSESSID] = $this->meta[session][RPCSESSID];
481 }
482
483 }
484
485 ?>

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