/[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.7 - (hide annotations)
Sun Mar 9 15:51:44 2003 UTC (21 years, 5 months ago) by joko
Branch: MAIN
Changes since 1.6: +32 -13 lines
+ additional metadata for Autodia

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

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