/[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.8 - (show 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 <?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 *
9 *
10 * <b>Cvs-Log:</b>
11 *
12 * <pre>
13 * -------------------------------------------------------------------------
14 * $Id: RemoteProxy.php,v 1.7 2003/03/09 15:51:44 joko Exp $
15 * -------------------------------------------------------------------------
16 * $Log: RemoteProxy.php,v $
17 * Revision 1.7 2003/03/09 15:51:44 joko
18 * + additional metadata for Autodia
19 *
20 * Revision 1.6 2003/03/05 17:28:43 joko
21 * updated docu (phpDocumentor testing....)
22 *
23 * Revision 1.5 2003/03/05 17:02:22 joko
24 * updated docu (phpDocumentor testing....)
25 *
26 * Revision 1.4 2003/03/05 16:32:19 joko
27 * updated docu (phpDocumentor testing....)
28 *
29 * Revision 1.3 2003/03/05 16:10:17 joko
30 * updated docu (phpDocumentor testing....)
31 *
32 * Revision 1.2 2003/03/05 12:14:02 joko
33 * renamed method
34 * constructor argument expansion
35 *
36 * Revision 1.1 2003/03/03 22:06:46 joko
37 * refactored from Data::Driver::Proxy
38 *
39 * 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 * </pre>
124 *
125 */
126
127
128
129
130 /**
131 * Load required modules:
132 *
133 */
134 loadModule('DesignPattern::Proxy');
135
136
137 /**
138 * DesignPattern::RemoteProxy -- Multiple stage data fetching and caching
139 *
140 *
141 * This class (DesignPattern::RemoteProxy) provides an abstract framework
142 * 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 * 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 * Multiple stage data fetching and caching:
157 *
158 * <pre>
159 *
160 * 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 * </pre>
203 *
204 *
205 * An attempt to implement some software design patterns
206 * --- RemoteProxyPattern
207 *
208 * @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 * @link http://c2.com/cgi-bin/wiki?ProxyPattern
212 * @link http://c2.com/cgi-bin/wiki?LazyProxies
213 *
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 * @subpackage DesignPattern
223 * @name DesignPattern::RemoteProxy
224 *
225 *
226 * @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 *
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 // 2003-03-05 - modified constructor
251 // expand objectId
252 if (is_array($objectId)) {
253 $options = $objectId[1];
254 $objectId = $objectId[0];
255 }
256
257 // 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 //print Dumper($this);
266
267 }
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
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
296 if ($this->meta[remote]) {
297 //$this->backend = mkObject('Data::Driver::RPC::Remote', $this->meta[rpcinfo]);
298 $this->backend = php::mkComponent('DataSource::Proxy::XMLRPC', $this->meta[rpcinfo]);
299 }
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 function getResult() {
357 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