/[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.8 - (hide 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 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.8 ## $Id: XMLRPC.php,v 1.7 2003/04/18 15:42:26 joko Exp $
15 joko 1.1 ## --------------------------------------------------------------------------
16 joko 1.2 ## $Log: XMLRPC.php,v $
17 joko 1.8 ## Revision 1.7 2003/04/18 15:42:26 joko
18     ## minor update to comment
19     ##
20 joko 1.7 ## 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 joko 1.6 ## Revision 1.5 2003/03/28 06:56:52 joko
25     ## updated logging/debugging code
26     ##
27 joko 1.5 ## Revision 1.4 2003/03/28 03:00:12 joko
28     ## enhanced error- and exception-handling
29     ##
30 joko 1.4 ## Revision 1.3 2003/03/27 16:05:01 joko
31     ## enhanced 'function _call': debugging, tracing and autodisconnect now parametrized
32     ##
33 joko 1.3 ## Revision 1.2 2003/03/05 23:16:48 joko
34     ## updated docu - phpDocumentor is very strict about its 'blocks'...
35     ##
36 joko 1.2 ## Revision 1.1 2003/03/03 21:53:52 joko
37     ## refactored from Data::Driver::RPC::Remote
38     ##
39 joko 1.1 ## 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 joko 1.2
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 joko 1.1 class DataSource_Proxy_XMLRPC extends Class_Logger {
109    
110     var $configured;
111 joko 1.4 var $meta = array();
112     var $response = null;
113     var $errors = array();
114 joko 1.1
115     function DataSource_Proxy_XMLRPC($args = array()) {
116    
117     parent::constructor();
118    
119     //print Dumper($this, $args);
120 joko 1.4 //print Dumper($args);
121 joko 1.1
122 joko 1.6 $this->_wakeup();
123 joko 1.1
124 joko 1.4 // force connect?
125    
126     // V1
127     /*
128 joko 1.1 if (!isset($this->meta[connected]) || $args[connect]) {
129     $this->meta[connected] = 1;
130     }
131 joko 1.4 */
132    
133     // V2
134     $this->FORCE_CONNECT = $args[connect];
135    
136 joko 1.1
137 joko 1.4
138 joko 1.3 // 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 joko 1.5 //print "key: $key<br/>";
149 joko 1.3 $key = strtoupper($key);
150     $this->$key = $val;
151     }
152     }
153 joko 1.1
154     // check if host is valid
155 joko 1.3 if (!$this->HOST) {
156 joko 1.1 $this->_raiseException( "->constructor: attribute 'host' is empty, please check your settings");
157     return;
158     }
159    
160 joko 1.3 if (!$this->PORT) {
161 joko 1.1 $this->_raiseException( "->constructor: attribute 'port' is empty, please check your settings");
162     return;
163     }
164    
165     $this->configured = 1;
166    
167     }
168    
169 joko 1.6 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 joko 1.1 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 joko 1.5 /*
186 joko 1.1 if (!$this->isConnected()) {
187 joko 1.3 $this->_raiseException( "->send[ command=$command ]: not connected while trying to send command!");
188 joko 1.1 return;
189     }
190 joko 1.5 */
191 joko 1.1
192     // do 'encode' here and ...
193     if ($options[utf8]) {
194     $encoder = new Data_Encode($data);
195     $encoder->toUTF8();
196 joko 1.8 $data = $encoder->get_result();
197 joko 1.1 }
198     // call '_call' with 'decode'
199     return $this->_call($command, $data, $options);
200     }
201    
202 joko 1.3
203 joko 1.1 function _call($command, $data = "", $options = array() ) {
204    
205 joko 1.6 $RETRY_COUNT = 0;
206     $RETRY_MAX = 1;
207 joko 1.1
208 joko 1.6 do {
209 joko 1.1
210 joko 1.6 $RETRY_COUNT++;
211 joko 1.1
212 joko 1.6 $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 joko 1.4
278 joko 1.1 // message - response
279 joko 1.4 $response_enc = $this->response->value();
280 joko 1.3
281     // TODO: what's this? prematurely returning here should not be considered "stable"....
282 joko 1.6 $data = $this->decodeData($response_enc, $options);
283     $this->_hook_response($data);
284     return $data;
285 joko 1.1
286     }
287    
288 joko 1.3
289 joko 1.1 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 joko 1.8 $data = $encoder->get_result();
301 joko 1.1 //}
302    
303 joko 1.4 $this->_be_connected();
304    
305 joko 1.1 return $data;
306     } else {
307     //print "ERROR!<br>";
308     return 0;
309     }
310     }
311    
312 joko 1.4 function _be_connected() {
313     $this->meta[connected] = 1;
314 joko 1.6 $this->_sleep();
315 joko 1.4 }
316    
317     function _raiseException($message, $code = null) {
318    
319 joko 1.5 $classname = get_class($this);
320    
321 joko 1.6 if ($this->__exception_method) {
322     $message_full = $classname . '->' . $this->__exception_method . ': ' . $message;
323     }
324    
325 joko 1.4 // aggregate errors for this run/query
326 joko 1.6 $this->_add_error($message, $code);
327 joko 1.3
328     // spout out the error message of the raised exception
329 joko 1.6 $this->log($classname . $message_full, PEAR_LOG_ERR);
330 joko 1.3
331 joko 1.4 // 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 joko 1.3 $message = '->_raiseException: [DISCONNECT_ON_ERROR] done transparently. Please reconnect manually.';
337 joko 1.5 $this->_add_error($classname . $message, $code);
338     //$this->log($classname . $message, PEAR_LOG_WARNING);
339     $this->log($classname . $message, PEAR_LOG_ERR);
340 joko 1.3 $this->meta[connected] = 0;
341 joko 1.6 $this->_sleep();
342 joko 1.3 }
343 joko 1.1 }
344    
345     function isConnected() {
346     return $this->meta[connected];
347     }
348    
349     function ping() {
350     $this->_call('ping');
351 joko 1.4 }
352    
353 joko 1.6
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 joko 1.4 // Please look inside your {appname}/etc/hosts/{hostname}.php for toggling $this->DEBUG
396     if ($error_code = $this->response->faultCode()) {
397 joko 1.6 // 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 joko 1.4 }
403     }
404    
405 joko 1.6 //if ($this->DEBUG && $error_code = $msg_response->faultCode()) {
406 joko 1.4
407     function _add_error($message, $code) {
408     array_push( $this->errors, array(code => $code, message => $message) );
409     }
410    
411 joko 1.6 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 joko 1.1 }
419 joko 1.6
420 joko 1.1
421 joko 1.7 // TODO: introduce condition: just do if connection requires session and/or auth
422 joko 1.6 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 joko 1.1 }
484    
485     ?>

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