/[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.12 - (hide annotations)
Sat Mar 29 08:01:21 2003 UTC (21 years, 5 months ago) by joko
Branch: MAIN
Changes since 1.11: +12 -13 lines
modified ErrorBoxing

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

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