/[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.7 - (show annotations)
Fri Apr 18 15:42:26 2003 UTC (21 years, 4 months ago) by joko
Branch: MAIN
Changes since 1.6: +6 -2 lines
minor update to comment

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

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