/[cvs]/nfo/perl/libs/Data/Storage.pm
ViewVC logotype

Contents of /nfo/perl/libs/Data/Storage.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (show annotations)
Tue Oct 29 19:24:18 2002 UTC (21 years, 8 months ago) by joko
Branch: MAIN
Changes since 1.4: +65 -25 lines
- reduced logging
+ added some pod

1 # $Id: Storage.pm,v 1.4 2002/10/27 18:35:07 joko Exp $
2 #
3 # Copyright (c) 2002 Andreas Motl <andreas.motl@ilo.de>
4 #
5 # See COPYRIGHT section in pod text below for usage and distribution rights.
6 #
7 #################################
8 #
9 # $Log: Storage.pm,v $
10 # Revision 1.4 2002/10/27 18:35:07 joko
11 # + added pod
12 #
13 # Revision 1.3 2002/10/25 11:40:37 joko
14 # + enhanced robustness
15 # + more logging for debug-levels
16 # + sub dropDb
17 #
18 # Revision 1.2 2002/10/17 00:04:29 joko
19 # + sub createDb
20 # + sub isConnected
21 # + bugfixes regarding "deep recursion" stuff
22 #
23 # Revision 1.1 2002/10/10 03:43:12 cvsjoko
24 # + new
25 #
26 #################################
27
28 # aim_V1: should encapsulate Tangram, DBI, DBD::CSV and LWP:: to access them in an unordinary way ;)
29 # aim_V2: introduce a generic layered structure, refactor *SUBLAYER*-stuff, make (e.g.) this possible:
30 # - Perl Data::Storage[DBD::CSV] -> Perl LWP:: -> Internet HTTP/FTP/* -> Host Daemon -> csv-file
31
32 BEGIN {
33 $Data::Storage::VERSION = 0.01;
34 }
35
36
37 =head1 NAME
38
39 Data::Storage - Interface for accessing various Storage implementations for Perl in an independent way
40
41 =head1 SYNOPSIS
42
43 ... the basic way:
44
45
46 ... via inheritance:
47
48 use Data::Storage;
49 my $proxyObj = new HttpProxy;
50 $proxyObj->{url} = $url;
51 $proxyObj->{payload} = $content;
52 $self->{storage}->insert($proxyObj);
53
54 use Data::Storage;
55 my $proxyObj = HttpProxy->new(
56 url => $url,
57 payload => $content,
58 );
59 $self->{storage}->insert($proxyObj);
60
61
62 =head2 NOTE
63
64 This module heavily relies on DBI and Tangram, but adds a lot of additional bugs and quirks.
65 Please look at their documentation and this code for additional information.
66
67
68 =cut
69
70 # The POD text continues at the end of the file.
71
72
73 package Data::Storage;
74
75 use strict;
76 use warnings;
77
78 use Data::Storage::Locator;
79
80 my $TRACELEVEL = 0;
81
82 # get logger instance
83 my $logger = Log::Dispatch::Config->instance;
84
85 sub new {
86 my $invocant = shift;
87 my $class = ref($invocant) || $invocant;
88 #my @args = normalizeArgs(@_);
89
90 my $arg_locator = shift;
91 my $arg_options = shift;
92
93 #my $self = { STORAGEHANDLE => undef, @_ };
94 my $self = { STORAGEHANDLE => undef, locator => $arg_locator, options => $arg_options };
95 $logger->debug( __PACKAGE__ . "[$self->{locator}->{type}]" . "->new(@_)" );
96 return bless $self, $class;
97 }
98
99 sub AUTOLOAD {
100
101 # since this is a core function acting as dispatcher to $self->{STORAGEHANDLE},
102 # some sophisticated handling and filtering is needed to avoid things like
103 # - Deep recursion on subroutine "Data::Storage::AUTOLOAD"
104 # - Deep recursion on subroutine "Data::Storage::Handler::Abstract::AUTOLOAD"
105 # - Deep recursion on anonymous subroutine at [...]
106 # we also might filter log messages caused by logging itself in "advanced logging of AUTOLOAD calls"
107
108 my $self = shift;
109 our $AUTOLOAD;
110
111 # ->DESTROY would - if not declared - trigger an AUTOLOAD also
112 return if $AUTOLOAD =~ m/::DESTROY$/;
113
114 my $method = $AUTOLOAD;
115 $method =~ s/^.*:://;
116
117 # advanced logging of AUTOLOAD calls ...
118 # ... nice but do it only when TRACING (TODO) is enabled
119 if ($TRACELEVEL) {
120 my $logstring = "";
121 $logstring .= __PACKAGE__ . "[$self->{locator}->{type}]" . "->" . $method;
122 #print "count: ", $#_, "\n";
123 #$logstring .= Dumper(@_) if ($#_ != -1);
124 my $tabcount = int( (80 - length($logstring)) / 10 );
125 $logstring .= "\t" x $tabcount . "(AUTOLOAD)";
126 # TODO: only ok if logstring doesn't contain
127 # e.g. "Data::Storage[Tangram]->insert(SystemEvent=HASH(0x5c0034c)) (AUTOLOAD)"
128 # but that would be way too specific as long as we don't have an abstract handler for this ;)
129 $logger->debug( $logstring );
130 }
131
132 # filtering AUTOLOAD calls
133 if ($self->_filter_AUTOLOAD($method)) {
134 $self->_accessStorage();
135 $self->{STORAGEHANDLE}->$method(@_);
136 }
137
138 }
139
140 sub _filter_AUTOLOAD {
141 my $self = shift;
142 my $method = shift;
143 if ($self->{options}->{protected}) {
144 if ($method eq 'disconnect') {
145 return;
146 }
147 }
148 return 1;
149 }
150
151
152 sub normalizeArgs {
153 my %args = @_;
154 if (!$args{dsn} && $args{meta}{dsn}) {
155 $args{dsn} = $args{meta}{dsn};
156 }
157 my @result = %args;
158 return @result;
159 }
160
161 sub _accessStorage {
162 my $self = shift;
163 # TODO: to some tracelevel!
164 if ($TRACELEVEL) {
165 $logger->debug( __PACKAGE__ . "[$self->{locator}->{type}]" . "->_accessStorage()" );
166 }
167 if (!$self->{STORAGEHANDLE}) {
168 $self->_createStorageHandle();
169 }
170 }
171
172 sub _createStorageHandle {
173 my $self = shift;
174
175 my $type = $self->{locator}->{type};
176 $logger->debug( __PACKAGE__ . "[$type]" . "->_createStorageHandle()" );
177
178 my $pkg = "Data::Storage::Handler::" . $type . "";
179
180 # propagate args to handler
181 # needs some more thoughts! (not only "dbi" to Tangram, when (in future) db is not more the common case)
182 if ($type eq 'DBI') {
183 use Data::Storage::Handler::DBI;
184 #my @args = %{$self->{locator}->{dbi}};
185 my @args = %{$self->{locator}};
186 # create new storage handle
187 $self->{STORAGEHANDLE} = $pkg->new( @args );
188 }
189 if ($type eq 'Tangram') {
190 use Data::Storage::Handler::Tangram;
191 #$self->{STORAGEHANDLE} = $pkg->new( dsn => $self->{locator}->{dbi}->{dsn} );
192 #my @args = %{$self->{locator}->{dbi}};
193 my @args = %{$self->{locator}};
194 # create new storage handle
195 $self->{STORAGEHANDLE} = $pkg->new( @args );
196
197 #$self->{STORAGEHANDLE_UNDERLYING} = $self->{STORAGEHANDLE}->getUnderlyingStorage();
198 #$self->{STORAGEHANDLE_UNDERLYING}->_configureCOREHANDLE();
199 }
200
201 }
202
203 sub addLogDispatchHandler {
204
205 my $self = shift;
206 my $name = shift;
207 my $package = shift;
208 my $logger1 = shift;
209 my $objectCreator = shift;
210
211 #$logger->add( Log::Dispatch::Tangram->new( name => $name,
212 $logger->add( $package->new( name => $name,
213 #min_level => 'debug',
214 min_level => 'info',
215 storage => $self,
216 objectCreator => $objectCreator,
217 fields => {
218 message => 'usermsg',
219 timestamp => 'stamp',
220 level => 'level',
221 name => 'code',
222 },
223 filter_patterns => [ '->insert\(SystemEvent=' ],
224 #filter_patterns => [ 'SystemEvent' ],
225
226 #format => '[%d] [%p] %m%n',
227 ) );
228
229 }
230
231 sub removeLogDispatchHandler {
232
233 my $self = shift;
234 my $name = shift;
235 #my $logger = shift;
236
237 $logger->remove($name);
238
239 }
240
241 sub getDbName {
242 my $self = shift;
243 my $dsn = $self->{locator}->{dbi}->{dsn};
244 $dsn =~ m/database=(.+?);/;
245 my $database_name = $1;
246 return $database_name;
247 }
248
249 sub testDsn {
250 my $self = shift;
251 my $dsn = $self->{locator}->{dbi}->{dsn};
252 my $result;
253 if ( my $dbh = DBI->connect($dsn, '', '', {
254 PrintError => 0,
255 } ) ) {
256 $dbh->disconnect();
257 return 1;
258 } else {
259 $logger->error( __PACKAGE__ . "[$self->{locator}->{type}]" . "->testDsn(): " . "DBI-error: " . $DBI::errstr );
260 }
261 }
262
263 sub createDb {
264 my $self = shift;
265 my $dsn = $self->{locator}->{dbi}->{dsn};
266
267 $logger->debug( __PACKAGE__ . "->createDb( dsn $dsn )" );
268
269 $dsn =~ s/database=(.+?);//;
270 my $database_name = $1;
271
272 my $ok;
273
274 if ( my $dbh = DBI->connect($dsn, '', '', {
275 PrintError => 0,
276 } ) ) {
277 if ($database_name) {
278 if ($dbh->do("CREATE DATABASE $database_name;")) {
279 $ok = 1;
280 }
281 }
282 $dbh->disconnect();
283 }
284
285 return $ok;
286
287 }
288
289 sub dropDb {
290 my $self = shift;
291 my $dsn = $self->{locator}->{dbi}->{dsn};
292
293 $logger->debug( __PACKAGE__ . "->dropDb( dsn $dsn )" );
294
295 $dsn =~ s/database=(.+?);//;
296 my $database_name = $1;
297
298 my $ok;
299
300 if ( my $dbh = DBI->connect($dsn, '', '', {
301 PrintError => 0,
302 } ) ) {
303 if ($database_name) {
304 if ($dbh->do("DROP DATABASE $database_name;")) {
305 $ok = 1;
306 }
307 }
308 $dbh->disconnect();
309 }
310
311 return $ok;
312 }
313
314 sub isConnected {
315 my $self = shift;
316 return 1 if $self->{STORAGEHANDLE};
317 }
318
319 1;
320 __END__
321
322
323 =head1 DESCRIPTION
324
325 Data::Storage is module for a accessing various "data structures" stored inside
326 various "data containers". It sits on top of DBI and/or Tangram.
327
328
329 =head1 AUTHORS / COPYRIGHT
330
331 The Data::Storage module is Copyright (c) 2002 Andreas Motl.
332 All rights reserved.
333
334 You may distribute it under the terms of either the GNU General Public
335 License or the Artistic License, as specified in the Perl README file.
336
337
338 =head1 ACKNOWLEDGEMENTS
339
340 Larry Wall and the C<perl5-porters> for Perl,
341 Tim Bunce for DBI, Jean-Louis Leroy for Tangram and Set::Object,
342 Sam Vilain for Class::Tangram.
343
344
345 =head1 SUPPORT / WARRANTY
346
347 Data::Storage is free software. IT COMES WITHOUT WARRANTY OF ANY KIND.
348
349
350 =head1 TODO
351
352
353 =head2 Handle the following errors/cases:
354
355 =head3 "DBI-Error [Tangram]: DBD::mysql::st execute failed: Unknown column 't1.requestdump' in 'field list'"
356
357 ... occours when operating on object-attributes not introduced yet:
358 this should be detected and appended/replaced through:
359 "Schema-Error detected, maybe (just) an inconsistency.
360 Please check if your declaration in schema-module "a" matches structure in database "b" or try to run"
361 db_setup.pl --dbkey=import --action=deploy
362
363 =head3 Compare schema (structure diff) with database ...
364
365 ... when issuing "db_setup.pl --dbkey=import --action=deploy"
366 on a database with an already deployed schema, use an additional "--update" then
367 to lift the schema inside the database to the current declared schema.
368 You will have to approve removals and changes on field-level while
369 new objects and new fields are introduced silently without any interaction needed.
370 In future versions there may be additional options to control silent processing of
371 removals and changes.
372 See this CRUD-table applying to the actions occouring on Classes and Class variables when deploying schemas,
373 don't mix this up with CRUD-actions on Objects, these are already handled by (e.g.) Tangram itself.
374 Classes:
375 C create -> yes, handled automatically
376 R retrieve -> no, not subject of this aspect since it is about deployment only
377 U update -> yes, automatically for Class meta-attributes, yes/no for Class variables (look at the rules down here)
378 D delete -> yes, just by user-interaction
379 Class variables:
380 C create -> yes, handled automatically
381 R retrieve -> no, not subject of this aspect since it is about deployment only
382 U update -> yes, just by user-interaction; maybe automatically if it can be determined that data wouldn't be lost
383 D delete -> yes, just by user-interaction
384
385 It's all about not to be able to loose data simply while this is in pre-alpha stage.
386 And loosing data by being able to modify and redeploy schemas easily is definitely quite easy.
387
388 As we can see, creations of Classes and new Class variables is handled
389 automatically and this is believed to be the most common case under normal circumstances.
390
391
392 =head2 Introduce some features:
393
394 - Get this stuff together with UML (Unified Modeling Language) and/or standards from ODMG.
395 - Make it possible to load/save schemas in XMI (XML Metadata Interchange),
396 which seems to be most commonly used today, perhaps handle objects with OIFML.
397 Integrate/bundle this with a web-/html-based UML modeling tool or
398 some other interesting stuff like the "Co-operative UML Editor" from Uni Darmstadt. (web-/java-based)
399 - Enable Round Trip Engineering. Keep code and diagrams in sync. Don't annoy/bother the programmers.
400 - Add some more handlers:
401 - look at DBD::CSV, Text::CSV, XML::CSV, XML::Excel
402 - Add some more locations/locators:
403 - PerlDAV: http://www.webdav.org/perldav/
404 - Move to t3, use InCASE
405
406
407 =head3 Links:
408
409 Specs:
410 UML 1.3 Spec: http://cgi.omg.org/cgi-bin/doc?ad/99-06-08.pdf
411 XMI 1.1 Spec: http://cgi.omg.org/cgi-bin/doc?ad/99-10-02.pdf
412 XMI 2.0 Spec: http://cgi.omg.org/docs/ad/01-06-12.pdf
413 ODMG: http://odmg.org/
414 OIFML: http://odmg.org/library/readingroom/oifml.pdf
415
416 CASE Tools:
417 Rational Rose (commercial): http://www.rational.com/products/rose/
418 Together (commercial): http://www.oi.com/products/controlcenter/index.jsp
419 InCASE - Tangram-based Universal Object Editor
420 Sybase PowerDesigner: http://www.sybase.com/powerdesigner
421
422 UML Editors:
423 Fujaba (free, university): http://www.fujaba.de/
424 ArgoUML (free): http://argouml.tigris.org/
425 Poseidon (commercial): http://www.gentleware.com/products/poseidonDE.php3
426 Co-operative UML Editor (research): http://www.darmstadt.gmd.de/concert/activities/internal/umledit.html
427 Metamill (commercial): http://www.metamill.com/
428 Violet (university, research, education): http://www.horstmann.com/violet/
429 PyUt (free): http://pyut.sourceforge.net/
430 (Dia (free): http://www.lysator.liu.se/~alla/dia/)
431 UMLet (free, university): http://www.swt.tuwien.ac.at/umlet/index.html
432 Voodoo (free): http://voodoo.sourceforge.net/
433
434 UML Tools:
435 http://www.objectsbydesign.com/tools/umltools_byPrice.html
436
437 Further readings:
438 http://www.google.com/search?q=web+based+uml+editor&hl=en&lr=&ie=UTF-8&oe=UTF-8&start=10&sa=N
439 http://www.fernuni-hagen.de/DVT/Aktuelles/01FHHeidelberg.pdf
440 http://www.enhyper.com/src/documentation/
441 http://cis.cs.tu-berlin.de/Dokumente/Diplomarbeiten/2001/skinner.pdf
442 http://citeseer.nj.nec.com/vilain00diagrammatic.html
443 http://archive.devx.com/uml/articles/Smith01/Smith01-3.asp
444

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