/[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.12 - (show annotations)
Sat Mar 29 08:01:21 2003 UTC (21 years, 3 months ago) by joko
Branch: MAIN
Changes since 1.11: +12 -13 lines
modified ErrorBoxing

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

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