/[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.9 - (show annotations)
Mon Mar 10 23:05:25 2003 UTC (21 years, 4 months ago) by joko
Branch: MAIN
Changes since 1.8: +8 -1 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 */
11
12
13 /**
14 * <b>Cvs-Log:</b>
15 *
16 * <pre>
17 * -------------------------------------------------------------------------
18 * $Id: RemoteProxy.php,v 1.8 2003/03/10 22:31:56 joko Exp $
19 * -------------------------------------------------------------------------
20 * $Log: RemoteProxy.php,v $
21 * Revision 1.8 2003/03/10 22:31:56 joko
22 * + fixed metadata for phpDocumentor
23 *
24 * Revision 1.7 2003/03/09 15:51:44 joko
25 * + additional metadata for Autodia
26 *
27 * Revision 1.6 2003/03/05 17:28:43 joko
28 * updated docu (phpDocumentor testing....)
29 *
30 * Revision 1.5 2003/03/05 17:02:22 joko
31 * updated docu (phpDocumentor testing....)
32 *
33 * Revision 1.4 2003/03/05 16:32:19 joko
34 * updated docu (phpDocumentor testing....)
35 *
36 * Revision 1.3 2003/03/05 16:10:17 joko
37 * updated docu (phpDocumentor testing....)
38 *
39 * Revision 1.2 2003/03/05 12:14:02 joko
40 * renamed method
41 * constructor argument expansion
42 *
43 * Revision 1.1 2003/03/03 22:06:46 joko
44 * refactored from Data::Driver::Proxy
45 *
46 * 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 * </pre>
131 *
132 */
133
134
135
136
137 /**
138 * Load required modules:
139 *
140 */
141 loadModule('DesignPattern::Proxy');
142
143
144 /**
145 * DesignPattern::RemoteProxy -- Multiple stage data fetching and caching
146 *
147 *
148 * This class (DesignPattern::RemoteProxy) provides an abstract framework
149 * 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 * 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 * Multiple stage data fetching and caching:
164 *
165 * <pre>
166 *
167 * 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 * </pre>
210 *
211 *
212 * An attempt to implement some software design patterns
213 * --- RemoteProxyPattern
214 *
215 * @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 * @link http://c2.com/cgi-bin/wiki?ProxyPattern
219 * @link http://c2.com/cgi-bin/wiki?LazyProxies
220 *
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 * @subpackage DesignPattern
230 * @name DesignPattern::RemoteProxy
231 *
232 *
233 * @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 *
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 // 2003-03-05 - modified constructor
258 // expand objectId
259 if (is_array($objectId)) {
260 $options = $objectId[1];
261 $objectId = $objectId[0];
262 }
263
264 // 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 //print Dumper($this);
273
274 }
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
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
303 if ($this->meta[remote]) {
304 //$this->backend = mkObject('Data::Driver::RPC::Remote', $this->meta[rpcinfo]);
305 $this->backend = php::mkComponent('DataSource::Proxy::XMLRPC', $this->meta[rpcinfo]);
306 }
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 function getResult() {
364 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