/[cvs]/nfo/php/libs/org.netfrag.glib/DesignPattern/RemoteProxy.php
ViewVC logotype

Annotation of /nfo/php/libs/org.netfrag.glib/DesignPattern/RemoteProxy.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (hide annotations)
Fri Apr 4 17:38:03 2003 UTC (21 years, 3 months ago) by joko
Branch: MAIN
Changes since 1.12: +46 -24 lines
modifications regarding error-/exception-handling and -tracing

1 joko 1.1 <?php
2 joko 1.3 /**
3     * This file contains the DesignPattern::RemoteProxy class
4     *
5     * @author Andreas Motl <andreas.motl@ilo.de>
6     * @package org.netfrag.glib
7     * @name DesignPattern::RemoteProxy
8     *
9 joko 1.4 *
10 joko 1.9 */
11    
12    
13     /**
14 joko 1.4 * <b>Cvs-Log:</b>
15     *
16     * <pre>
17 joko 1.1 * -------------------------------------------------------------------------
18 joko 1.13 * $Id: RemoteProxy.php,v 1.12 2003/03/29 08:01:21 joko Exp $
19 joko 1.1 * -------------------------------------------------------------------------
20 joko 1.2 * $Log: RemoteProxy.php,v $
21 joko 1.13 * Revision 1.12 2003/03/29 08:01:21 joko
22     * modified ErrorBoxing
23     *
24 joko 1.12 * Revision 1.11 2003/03/28 06:44:51 joko
25     * VERBOSE mode
26     *
27 joko 1.11 * Revision 1.10 2003/03/28 03:05:54 joko
28     * more fancy debugging-output
29     *
30 joko 1.10 * Revision 1.9 2003/03/10 23:05:25 joko
31     * + fixed metadata for phpDocumentor
32     *
33 joko 1.9 * Revision 1.8 2003/03/10 22:31:56 joko
34     * + fixed metadata for phpDocumentor
35     *
36 joko 1.8 * Revision 1.7 2003/03/09 15:51:44 joko
37     * + additional metadata for Autodia
38     *
39 joko 1.7 * Revision 1.6 2003/03/05 17:28:43 joko
40     * updated docu (phpDocumentor testing....)
41     *
42 joko 1.6 * Revision 1.5 2003/03/05 17:02:22 joko
43     * updated docu (phpDocumentor testing....)
44     *
45 joko 1.5 * Revision 1.4 2003/03/05 16:32:19 joko
46     * updated docu (phpDocumentor testing....)
47     *
48 joko 1.4 * Revision 1.3 2003/03/05 16:10:17 joko
49     * updated docu (phpDocumentor testing....)
50     *
51 joko 1.3 * Revision 1.2 2003/03/05 12:14:02 joko
52     * renamed method
53     * constructor argument expansion
54     *
55 joko 1.2 * Revision 1.1 2003/03/03 22:06:46 joko
56     * refactored from Data::Driver::Proxy
57     *
58 joko 1.1 * Revision 1.3 2003/03/01 04:56:38 joko
59     * new comment style for large blocks - stolen from phpHtmlLib
60     * commit-log encapsulated into such a block
61     * introduced some documentation
62     * refactored todo (now also inside a stylish block)
63     *
64     * Revision 1.2 2003/02/13 21:48:09 joko
65     * + caching mechanisms more configurable now
66     *
67     * Revision 1.1 2003/02/09 17:23:21 joko
68     * + refactored from flib/Application/RPC/ProxyObject.php
69     *
70     * Revision 1.7 2003/02/03 03:31:38 jonen
71     * - moved '$encoder->toISO()' to 'Remote.php'
72     *
73     * Revision 1.6 2002/12/22 13:26:20 jonen
74     * + added support of tangram independent id (e.g. Data::UUID) toggled by option at conrtuctor
75     *
76     * Revision 1.5 2002/12/18 22:36:49 jonen
77     * + added support to get remote objects via backend via 'guid'
78     * + renamed '_loadBackend' to '_loadRemote'
79     * + constructor now accepts additional options:
80     * + remote: try to get object via '_loadRemote' ...
81     * + oid: use the given identifier as an 'oid' when doing '_loadRemote'
82     * + guid: use the given identifier as a 'guid' when doing '_loadRemote'
83     *
84     * Revision 1.4 2002/12/12 02:46:31 joko
85     * + state (session) gets flushed when data was successfully loaded from remote side
86     * + fixed _loadBackend
87     * + fixed flushState
88     *
89     * Revision 1.3 2002/12/06 04:12:54 joko
90     * + replaced 'xyzCache' through 'xyzProxy'
91     * + function store(...)
92     *
93     * Revision 1.2 2002/12/05 21:44:09 joko
94     * + debugging
95     *
96     * Revision 1.1 2002/12/01 17:23:58 joko
97     * + initial check-in
98     *
99     * Revision 1.11 2002/11/12 06:05:58 cvsjoko
100     * + renamed class: Text_Encode -> TextEncode
101     *
102     * Revision 1.10 2002/10/29 19:15:33 cvsjoko
103     * - moved utf8/iso-conversion to lib/utils/Text_Encode.php
104     *
105     * Revision 1.9 2002/10/26 12:32:36 cvsjoko
106     * - removed debugging via "print"
107     * + added generic logging via PEAR::Log
108     *
109     * Revision 1.8 2002/10/22 09:51:38 cvsmax
110     * + moved semi-method 'createBackend' to method $site->user->create at User.class.php
111     *
112     * Revision 1.7 2002/10/21 18:27:09 cvsjoko
113     * - manually disabled any form of caching
114     *
115     * Revision 1.6 2002/10/17 03:48:47 cvsmax
116     * + new
117     * + function _createBackend create new Backend
118     * + function _create api-create
119     *
120     * Revision 1.5 2002/10/16 03:37:54 cvsjoko
121     * + bugfix: wrong comparison in restriction to save to array
122     *
123     * Revision 1.4 2002/10/10 03:04:23 cvsjoko
124     * + no debug-output
125     *
126     * Revision 1.3 2002/10/10 03:03:27 cvsjoko
127     * + bugfix: save object to cache only if payload from backend isn't empty
128     *
129     * Revision 1.2 2002/10/10 02:40:06 cvsjoko
130     * + new level of data-caching (session and persistant)
131     * + function _loadState loads data from session
132     * + function _saveState saves data to session
133     * + function save api-save (session & backend)
134     * + function _commit saves data to backend
135     * + handy utils
136     * + function _setAttributes
137     * + function flushState
138     *
139     * Revision 1.1 2002/10/09 00:51:39 cvsjoko
140     * + new
141     * -------------------------------------------------------------------------
142 joko 1.4 * </pre>
143     *
144 joko 1.1 */
145    
146 joko 1.4
147    
148    
149     /**
150     * Load required modules:
151     *
152     */
153     loadModule('DesignPattern::Proxy');
154    
155    
156 joko 1.1 /**
157 joko 1.7 * DesignPattern::RemoteProxy -- Multiple stage data fetching and caching
158 joko 1.1 *
159     *
160 joko 1.7 * This class (DesignPattern::RemoteProxy) provides an abstract framework
161 joko 1.1 * for loading/saving arbitrary data from/to data storages interfaced
162     * by storage *proxy*-drivers.
163     * Don't mix these up with the concrete storage *handle*-drivers
164     * doing the lowlevel stuff (opening files, talking sql, etc.).
165     * These proxy-drivers are "just" wrappers around them
166     * providing a more highlevel, consistent API making
167     * it easier for Data::Driver::Proxy to do its main work:
168     *
169 joko 1.7 * quote from: http://home.earthlink.net/~huston2/dp/proxy.html
170     * "A remote proxy provides a local representative for an
171     * object that resides in a different address space. This is
172     * what the "stub" code in RPC and CORBA provides."
173     *
174     *
175 joko 1.1 * Multiple stage data fetching and caching:
176     *
177 joko 1.4 * <pre>
178     *
179 joko 1.1 * DATA, ...
180     * ... also refered to as data, should be handled as
181     * something called data.
182     *
183     * STAGES
184     * x native php4 session: serialized payload
185     * x single rdbms table: serialized payload
186     * x ... via custom database wrapper
187     * x included php-file, included php-library
188     * o object, component, package, callbacks
189     * x ... via php PEAR DB abstraction objects
190     * x remote objects (items): flat attribute hash
191     * o use Data::Object::Identity
192     * o via Data::Driver::Proxy::RPC or others
193     * o Data::Object::Encoder: encodes/decodes values
194     * o Data::Object::Interpolator: interpolates/resolves references
195     *
196     * WORK
197     * x move data transparently around between these stages
198     *
199     * TOOLS
200     *
201     * x Overview - Packages, Handlers and Stages:
202     * This is weird. ;-)
203     * - A Package can be instantiated by its namespaced classname
204     * e.g.: "mkObject('My::Package');"
205     * - A Package can be a Handler for Data::Driver::Proxy
206     * - A Handler implements exactly one Stage
207     * - Data::Driver::Proxy itself embeds these Stages:
208     * x php4-session
209     * x rdbms-table
210     * - An example Handler is Data::Driver::RPC::Remote
211     *
212     * x Handlers:
213     * x Data::Driver::RPC::Remote
214     * Interacts with a RPC::XML server (todo: talk SOAP!)
215     * using PEAR::XML::RPC.
216     * It can cache data for "disconnected mode" using the
217     * o Data::Driver::phpHtmlLib
218     * o Data::Driver::PEAR::DB
219     * x Data::Driver::PEAR::Tree (via Data::Lift)
220     *
221 joko 1.4 * </pre>
222     *
223     *
224     * An attempt to implement some software design patterns
225 joko 1.3 * --- RemoteProxyPattern
226     *
227 joko 1.7 * @link http://www.agcs.com/supportv2/techpapers/patterns/papers/tutnotes/sld017.htm
228     * @link http://home.earthlink.net/~huston2/dp/proxy.html
229     * @link http://wiki.cs.uiuc.edu/PatternStories/RemoteObject
230 joko 1.3 * @link http://c2.com/cgi-bin/wiki?ProxyPattern
231 joko 1.7 * @link http://c2.com/cgi-bin/wiki?LazyProxies
232 joko 1.3 *
233     * @author Andreas Motl <andreas.motl@ilo.de>
234     * @link http://www.netfrag.org/~joko/
235     *
236     * @copyright (c) 2003 - All Rights reserved.
237     * @license GNU LGPL (GNU Lesser General Public License)
238     * @link http://www.gnu.org/licenses/lgpl.txt
239     *
240     * @package org.netfrag.glib
241 joko 1.6 * @subpackage DesignPattern
242 joko 1.3 * @name DesignPattern::RemoteProxy
243     *
244 joko 1.4 *
245 joko 1.7 * @todo extend options to en-/disable caching via a) session and/or b) database
246     * make feature available via runtime setter-method to these options
247     * @todo PEAR::Cache for caching purposes!!!
248     * @todo refactor database access: use PEAR for this! no more 'connectdb' here!!!
249     * @todo make database connection more flexible to make possible
250     * to have different (probably named) proxy databases (besides a "main database")
251     * @todo rename this to Data::Proxy? or split into Data::Query, Data::Result and Data::Wrapper?
252     * @todo refactor this to a "RemoteObject" class!!! (inheriting from DesignPattern::RemoteObject)
253     * @todo rename this to "DesignPattern::LazyRemoteProxy"???
254 joko 1.1 *
255     */
256     class DesignPattern_RemoteProxy extends DesignPattern_Proxy {
257    
258     var $objectId;
259     // purpose ...
260     var $meta;
261     var $payload;
262     var $attributes;
263     var $backend;
264    
265     function DesignPattern_RemoteProxy($objectId = "", $options = array() ) {
266     logp(get_class($this) . "->new()", PEAR_LOG_INFO);
267     global $proxy;
268    
269 joko 1.2 // 2003-03-05 - modified constructor
270     // expand objectId
271     if (is_array($objectId)) {
272     $options = $objectId[1];
273     $objectId = $objectId[0];
274     }
275    
276 joko 1.1 // trace
277     //print Dumper($objectId, $options);
278    
279     // initialization/startup
280     $this->_init_meta_options($objectId, $options);
281     $this->_init_caching();
282     $this->_init_load();
283    
284 joko 1.2 //print Dumper($this);
285    
286 joko 1.1 }
287    
288     function _init_meta_options( $objectId="", $options = array() ) {
289     $this->meta = $options;
290    
291     if ($objectId) {
292     $this->objectId = $objectId;
293    
294     // set default load mechanism
295     if ( $this->meta[remote] && ((!$this->meta[oid] && !$this->meta[guid]) || ($this->meta[oid] && $this->meta[guid])) && (!$this->meta[key]) ) {
296     $this->meta[oid] = 1;
297     }
298    
299     }
300     }
301    
302     function _init_caching() {
303    
304     if ($this->meta[cache][session]) {
305     session_register_safe("proxy");
306     }
307 joko 1.7
308     /**
309     * <!-- Autodia -->
310     * can do: (this is metadata supplied for Autodia, don't delete!)
311     * $this->backend = new DataSource_Proxy_XMLRPC()
312     *
313     */
314 joko 1.1
315     if ($this->meta[remote]) {
316     //$this->backend = mkObject('Data::Driver::RPC::Remote', $this->meta[rpcinfo]);
317 joko 1.2 $this->backend = php::mkComponent('DataSource::Proxy::XMLRPC', $this->meta[rpcinfo]);
318 joko 1.1 }
319     }
320    
321     function _init_load() {
322     if ($this->objectId) {
323     $this->load();
324     //$this->_saveProxy();
325     }
326     }
327    
328    
329     function load() {
330     logp(get_class($this) . "->load()", PEAR_LOG_INFO);
331     if (!$this->_loadState()) {
332     if (!$this->_loadProxy()) {
333    
334     // just load object from remote side if its flagged to be a remote one ...
335     if ($this->meta[remote]) {
336     $this->_loadRemote();
337     }
338    
339     }
340     }
341     }
342    
343     function save($data, $type) {
344     $this->_setAttributes($data);
345     $this->_saveState();
346     if ($type == 'commit') {
347     $this->_commit();
348     }
349     if ($type == 'create') {
350     $this->_create();
351     }
352     }
353    
354     function flush() {
355     $this->flushState();
356     $this->flushProxy();
357     }
358    
359     function _commit() {
360     $this->_saveBackend($this->attributes);
361     $this->flushState();
362     $this->flushProxy();
363     }
364    
365    
366     // TODO: make this work
367     /*
368     function _create() {
369     $this->_createBackend($this->attributes);
370     $this->flushState();
371     $this->flushProxy();
372     }
373     */
374    
375 joko 1.2 function getResult() {
376 joko 1.1 if (!$this->meta[decoded]) {
377     $this->_decode();
378     $this->_saveState();
379     }
380     return $this->attributes;
381     }
382    
383     function _setAttributes($data) {
384     $this->attributes = $data;
385     }
386    
387     function flushProxy() {
388     connectdb();
389     $sql = "DELETE FROM f_proxy WHERE oid='$this->objectId'";
390     send_sql($sql);
391     }
392    
393     function flushState() {
394     global $proxy;
395     unset($proxy[$this->objectId]);
396     $this->meta[decoded] = 0;
397     }
398    
399     function _loadState() {
400     global $proxy;
401    
402     // trace
403     //print Dumper($this);
404    
405     // debug
406     logp(get_class($this) . "->_loadState()");
407    
408     if ($this->attributes = $proxy[$this->objectId]) {
409     //print "_loadState:" . dumpVar($this->attributes);
410     $this->meta[decoded] = 1;
411     // TODO: make a parameter from this (0 deactivates session-layer)
412     return 0;
413     }
414     }
415    
416     function _saveState() {
417     global $proxy;
418     logp(get_class($this) . "->_saveState()");
419     $proxy[$this->objectId] = $this->attributes;
420     //print "_saveState: " . dumpVar($this->attributes);
421     // TODO: throw exception-message back to user if operation fails
422     }
423    
424     function _loadProxy() {
425    
426     // FIXME!
427     if (!$this->meta[cache][db]) { return; }
428    
429     // trace & debug
430     //print Dumper($this);
431     logp(get_class($this) . "->_loadProxy()");
432    
433     connectdb();
434     $sql = "SELECT payload FROM f_proxy WHERE oid='$this->objectId'";
435     if ($res = send_sql($sql)) {
436     $row = mysql_fetch_array($res, MYSQL_ASSOC);
437     if ($row) {
438     $this->payload = $row[payload];
439     // TODO: make a parameter from this (0 deactivates mysqldb-layer)
440     return 0;
441     }
442     }
443     }
444    
445     // TODO: use PEAR here
446     function _saveProxy() {
447    
448     // FIXME!
449     if (!$this->meta[cache][db]) { return; }
450    
451     logp(get_class($this) . "->_saveProxy()");
452     connectdb();
453     if ($this->payload) {
454     //$sql = "INSERT INTO f_proxy SET payload='$this->payload' WHERE oid='$this->objectId'";
455     $sql = "INSERT INTO f_proxy SET oid='$this->objectId', payload='$this->payload'";
456     if (!send_sql($sql)) {
457     $sql = "UPDATE f_proxy SET payload='$this->payload' WHERE oid='$this->objectId'";
458     send_sql($sql);
459     }
460     }
461     }
462    
463     function _loadRemote() {
464     logp(get_class($this) . "->_loadRemote()");
465    
466     // trace
467     //print Dumper($this->meta);
468    
469     // TODO: test backend for reachability first (eventually cache this information and "reset" it by another party)
470    
471     // 1. check backend-handle
472     if (!$this->backend) {
473     logp(get_class($this) . "->_loadRemote: no backend handle, please check argument 'rpcinfo'", PEAR_LOG_CRIT);
474     return;
475     }
476    
477     // determine backend action by metadata
478     // check for guid or oid
479     if ($this->meta[guid]) {
480     if (!$this->objectId) {
481     logp(get_class($this) . "->_loadRemote: argument 'guid' requires valid objectId", PEAR_LOG_WARNING);
482     return;
483     }
484     if (!$this->meta[classname]) {
485     logp(get_class($this) . "->_loadRemote: argument 'guid' requires 'classname'", PEAR_LOG_WARNING);
486     return;
487     }
488 joko 1.10 logp(get_class($this) . "->_loadRemote: getObjectByGuid", PEAR_LOG_DEBUG);
489 joko 1.1 $args = array( guid => $this->objectId, classname => $this->meta[classname] );
490     $result = $this->backend->send('getObjectByGuid', $args );
491    
492     } elseif ($this->meta[oid]) {
493     if (!$this->objectId) {
494     logp(get_class($this) . "->_loadRemote: argument 'oid' requires valid objectId", PEAR_LOG_WARNING);
495     return;
496     }
497 joko 1.10 logp(get_class($this) . "->_loadRemote: getObject", PEAR_LOG_DEBUG);
498 joko 1.1 $result = $this->backend->send('getObject', $this->objectId);
499    
500     } elseif ($this->meta[key]) {
501     if (!$this->meta[command]) {
502     logp(get_class($this) . "->_loadRemote: argument 'key' requires 'command'", PEAR_LOG_WARNING);
503     return;
504     }
505     /*
506     if (!$this->meta[query]) {
507     logp(get_class($this) . "->_loadRemote: argument 'key' requires 'query'", PEAR_LOG_WARNING);
508     return;
509     }
510     */
511 joko 1.10 //logp(get_class($this) . "->_loadRemote: $this->meta[command](" . join(' ', $this->meta[query]) . ")", PEAR_LOG_DEBUG);
512     //print Dumper(array($this->meta[command], $this->meta[query]));
513 joko 1.1 $result = $this->backend->send($this->meta[command], $this->meta[query]);
514    
515     }
516    
517 joko 1.10 //print "result: " . dumpVar($result) . "<br>";
518 joko 1.1
519 joko 1.13 $status = $this->backend->status();
520 joko 1.10 //print Dumper($status);
521    
522 joko 1.13 $good = is_array($result) && sizeof($result) && $status[connected];
523 joko 1.10
524 joko 1.13 if ($good) {
525 joko 1.1
526     // FIXME: this is dangerous!
527 joko 1.13 /*
528 joko 1.1 if ($_GET[debug]) {
529     print Dumper($result);
530     }
531 joko 1.13 */
532 joko 1.1
533     $this->payload = serialize($result);
534     // ----- move this to _encode some times
535    
536     $this->_saveProxy();
537     //print "oid: $this->objectId<br>";
538     $this->flushState();
539 joko 1.10
540 joko 1.1 } else {
541 joko 1.13
542     if (constants::get('APP_MODE_DEBUG')) {
543     $this->draw_error_box($status);
544 joko 1.11 } else {
545 joko 1.13 php::maintenance('rpc', array( status => $status ) );
546 joko 1.11 }
547 joko 1.10
548 joko 1.1 }
549    
550     }
551 joko 1.13
552     function draw_error_box($status) {
553     $style = html_style("text/css", '.boxlabel_yellow { color: yellow; font-weight:bold; }');
554     $statusbox = html_div();
555     $statusbox->set_style('background: red; border: 2px black groove; width:640px; padding:10px; margin:40px;');
556     $statusbox->add( html_span('boxlabel_yellow', "Method:"), get_class($this) . "->_loadRemote", html_br() );
557     $statusbox->add( html_span('boxlabel_yellow', "Connected:"), $status[connected], html_br() );
558     $statusbox->add( html_span('boxlabel_yellow', "RPCSESSID:"), $status[RPCSESSID], html_br() );
559     foreach ($status[errors] as $error) {
560     $statusbox->add( html_span('boxlabel_yellow', "Error($error[code]):"), $error[message], html_br() );
561     }
562 joko 1.1
563 joko 1.13 $message = "Error while talking to remote side. Please check wire, socket or api.";
564     logp($message, PEAR_LOG_CRIT);
565     $statusbox->add( html_span('boxlabel_yellow', "Critical:"), $message, html_br() );
566    
567     // V1
568     /*
569     if (constants::get('VERBOSE') || constants::get('ERRORS_ONLY')) {
570     print $style->render();
571     print $statusbox->render();
572     } else {
573     foreach ($status[errors] as $error) {
574     print Dumper($error);
575     }
576     }
577     */
578    
579     // V2
580     trace( container($style, $statusbox) );
581    
582     }
583    
584    
585 joko 1.1 function _saveBackend($result) {
586     logp(get_class($this) . "->_saveBackend()");
587    
588     //$encoder = new TextEncode($result);
589     //$encoder->toUTF8();
590    
591     // check for guid or oid
592     if($this->meta[guid]) {
593     $args = array( 'guid' => $this->objectId, 'classname' => $this->meta[classname], 'data' => $result );
594     $response = $this->backend->send('saveObjectByGuid', $args, array( utf8 => 1) );
595     }
596     if($this->meta[oid]) {
597     $response = $this->backend->send('saveObject', array('oid' => $this->objectId, 'data' => $result), array( utf8 => 1) );
598     }
599     }
600    
601     function _decode() {
602     // fill attributes-hashtable from message-hashtable
603     if (!$this->payload) { return; }
604     //if ($this->attributes = $backend->decodeData($this->payload)) {
605     if ($this->attributes = unserialize($this->payload)) {
606     $this->meta[decoded] = 1;
607     }
608     }
609    
610     function store($struct) {
611     $this->payload = serialize($struct);
612     $this->_saveProxy();
613     }
614    
615     }
616    
617     ?>

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