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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (hide annotations)
Fri Apr 4 21:23:29 2003 UTC (21 years, 4 months ago) by joko
Branch: MAIN
Changes since 1.5: +211 -65 lines
session-based rpc-communcation: revamped code (especially 'function _call')
renamed state-handling trigger-methods: now _sleep and _wakeup

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

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