/[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.8 - (hide annotations)
Mon Mar 10 22:31:56 2003 UTC (21 years, 4 months ago) by joko
Branch: MAIN
Changes since 1.7: +4 -2 lines
+ fixed metadata for phpDocumentor

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

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