/[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.10 - (hide annotations)
Fri Mar 28 03:05:54 2003 UTC (21 years, 3 months ago) by joko
Branch: MAIN
Changes since 1.9: +34 -6 lines
more fancy debugging-output

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

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