/[cvs]/nfo/php/libs/org.netfrag.glib/DesignPattern/RemoteProxy.php
ViewVC logotype

Contents of /nfo/php/libs/org.netfrag.glib/DesignPattern/RemoteProxy.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (show annotations)
Sun Mar 9 15:51:44 2003 UTC (21 years, 4 months ago) by joko
Branch: MAIN
Changes since 1.6: +32 -13 lines
+ additional metadata for Autodia

1 <?php
2 /**
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 * @filesource
9 *
10 *
11 * <b>Cvs-Log:</b>
12 *
13 * <pre>
14 * -------------------------------------------------------------------------
15 * $Id: RemoteProxy.php,v 1.6 2003/03/05 17:28:43 joko Exp $
16 * -------------------------------------------------------------------------
17 * $Log: RemoteProxy.php,v $
18 * Revision 1.6 2003/03/05 17:28:43 joko
19 * updated docu (phpDocumentor testing....)
20 *
21 * Revision 1.5 2003/03/05 17:02:22 joko
22 * updated docu (phpDocumentor testing....)
23 *
24 * Revision 1.4 2003/03/05 16:32:19 joko
25 * updated docu (phpDocumentor testing....)
26 *
27 * Revision 1.3 2003/03/05 16:10:17 joko
28 * updated docu (phpDocumentor testing....)
29 *
30 * Revision 1.2 2003/03/05 12:14:02 joko
31 * renamed method
32 * constructor argument expansion
33 *
34 * Revision 1.1 2003/03/03 22:06:46 joko
35 * refactored from Data::Driver::Proxy
36 *
37 * 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 * </pre>
122 *
123 */
124
125
126
127
128 /**
129 * Load required modules:
130 *
131 */
132 loadModule('DesignPattern::Proxy');
133
134
135 /**
136 * DesignPattern::RemoteProxy -- Multiple stage data fetching and caching
137 *
138 *
139 * This class (DesignPattern::RemoteProxy) provides an abstract framework
140 * 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 * 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 * Multiple stage data fetching and caching:
155 *
156 * <pre>
157 *
158 * 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 * </pre>
201 *
202 *
203 * An attempt to implement some software design patterns
204 * --- RemoteProxyPattern
205 *
206 * @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 * @link http://c2.com/cgi-bin/wiki?ProxyPattern
210 * @link http://c2.com/cgi-bin/wiki?LazyProxies
211 *
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 * @subpackage DesignPattern
221 * @name DesignPattern::RemoteProxy
222 *
223 *
224 * @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 *
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 // 2003-03-05 - modified constructor
249 // expand objectId
250 if (is_array($objectId)) {
251 $options = $objectId[1];
252 $objectId = $objectId[0];
253 }
254
255 // 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 //print Dumper($this);
264
265 }
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
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
294 if ($this->meta[remote]) {
295 //$this->backend = mkObject('Data::Driver::RPC::Remote', $this->meta[rpcinfo]);
296 $this->backend = php::mkComponent('DataSource::Proxy::XMLRPC', $this->meta[rpcinfo]);
297 }
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 function getResult() {
355 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