/[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.16 - (hide annotations)
Wed Jul 2 13:51:38 2003 UTC (21 years, 1 month ago) by jonen
Branch: MAIN
Changes since 1.15: +5 -2 lines
removed debug dumper

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

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