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

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