/[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.4 - (show annotations)
Sun Oct 27 18:35:07 2002 UTC (21 years, 8 months ago) by joko
Branch: MAIN
Changes since 1.3: +148 -4 lines
+ added pod

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

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