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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.8

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