/[cvs]/nfo/perl/libs/Data/Transfer/Sync/API.pm
ViewVC logotype

Contents of /nfo/perl/libs/Data/Transfer/Sync/API.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show annotations)
Mon Jan 20 16:59:48 2003 UTC (21 years, 5 months ago) by joko
Branch: MAIN
Changes since 1.1: +93 -52 lines
+ cosmetics and debugging

1 ## $Id: API.pm,v 1.1 2003/01/19 01:23:04 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 ## $Log: API.pm,v $
9 ## Revision 1.1 2003/01/19 01:23:04 joko
10 ## + new from Data/Transfer/Sync.pm
11 ##
12 ## ----------------------------------------------------------------------------------------
13
14
15 package Data::Transfer::Sync::API;
16
17 use strict;
18 use warnings;
19
20 use mixin::with qw( Data::Transfer::Sync );
21
22
23 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - main
24
25 use Data::Dumper;
26
27 use Data::Compare::Struct qw( getDifference isEmpty );
28 use Data::Transform::Deep qw( merge );
29
30 # get logger instance
31 my $logger = Log::Dispatch::Config->instance;
32
33 sub _init {
34 my $self = shift;
35 }
36
37 sub checkOptions {
38 my $self = shift;
39 my $opts = shift;
40
41 my $result = 1;
42
43 # check - do we have a target node?
44 if (!$opts->{target_node}) {
45 $logger->warning( __PACKAGE__ . "->checkOptions: Error while resolving resource metadata - no 'target node' could be determined.");
46 $result = 0;
47 }
48
49 # check - do we have a mapping?
50 if (!$opts->{mapping} && !$opts->{mapping_module}) {
51 $logger->warning( __PACKAGE__ . "->checkOptions: Error while resolving resource metadata - no 'mapping' could be determined.");
52 $result = 0;
53 }
54
55 return $result;
56
57 }
58
59 sub checkOptionsV2 {
60 my $self = shift;
61
62 #print Dumper($self->{options});
63
64 my $result = 1;
65
66 # check - do we have a target node?
67 if (!$self->{options}->{target}->{nodeName}) {
68 $logger->warning( __PACKAGE__ . "->checkOptionsV2: No target given - please check metadata declaration.");
69 $result = 0;
70 }
71
72 # check - do we have a mapping?
73 if (!$self->{options}->{fieldmap}) {
74 $logger->warning( __PACKAGE__ . "->checkOptionsV2: Error while resolving resource metadata - no 'fieldmap' could be determined.");
75 $result = 0;
76 }
77
78 # TODO: extend!
79
80 return $result;
81
82 }
83
84
85 sub prepareOptions {
86
87 my $self = shift;
88 my $opts = shift;
89
90 #print Dumper($opts);
91 #exit;
92
93 $opts->{mode} ||= '';
94 $opts->{erase} ||= 0;
95 $opts->{prepare} ||= 0;
96 #$opts->{import} ||= 0;
97
98 if (!$opts->{source_node}) {
99 $logger->error( __PACKAGE__ . "->prepareOptions failed: Please specify source-node!");
100 return;
101 }
102
103 $logger->notice( __PACKAGE__ . "->prepareOptions( source_node $opts->{source_node} mode $opts->{mode} erase $opts->{erase} prepare $opts->{prepare} )");
104
105 #if (!$opts->{mapping} || !$opts->{mapping_module}) {
106 if (!$opts->{mapping}) {
107 $logger->warning( __PACKAGE__ . "->prepareOptions: No mapping supplied - please check key 'mappings' in global configuration or specify additional argument '--mapping'.");
108 #return;
109 }
110
111 $opts->{mapping_module} ||= $opts->{mapping};
112 my $evstring = "use $opts->{mapping_module};";
113 eval($evstring);
114 if ($@) {
115 $logger->warning( __PACKAGE__ . "->prepareOptions: error while trying to access mapping - $@");
116 return;
117 }
118
119 # resolve mapping metadata (returned from sub)
120 my $mapObject = $opts->{mapping_module}->new();
121 #print Dumper($map);
122 my $source_node_name = $opts->{source_node};
123 # check if mapping for certain node is contained in mapping object
124 if (!$mapObject->can($source_node_name)) {
125 $logger->warning( __PACKAGE__ . "->prepareOptions: Can't access mapping for node \"$source_node_name\" - please check $opts->{mapping_module}.");
126 return;
127 }
128 my $map = $mapObject->$source_node_name;
129
130 #print Dumper($map);
131
132 # check here if "target" is actually a CODEref - in this case: resolve it - deprecated!!! ???
133 if (ref $map->{target} eq 'CODE') {
134 $map->{target} = $map->{target}->($source_node_name);
135 }
136
137 # resolve expressions (on nodename-level) here
138 if ($map->{target} =~ m/^(code|expr):(.+?)$/) {
139 my $target_dynamic_type = $1;
140 my $target_dynamic_expression = $2;
141 if (lc $target_dynamic_type eq 'code') {
142 # $map->{target} = $mapObject->$target_dynamic_expression($map);
143 }
144 }
145
146 # remove asymmetries from $map (patch keys)
147 $map->{source_node} = $map->{source}; delete $map->{source};
148 $map->{target_node} = $map->{target}; delete $map->{target};
149 $map->{mapping} = $map->{details}; delete $map->{details};
150 $map->{direction} = $map->{mode}; delete $map->{mode};
151
152 # defaults (mostly for backward-compatibility)
153 $map->{source_node} ||= $source_node_name;
154 $map->{source_ident} ||= 'storage_method:id';
155 $map->{target_ident} ||= 'property:oid';
156 $map->{direction} ||= $opts->{mode}; # | PUSH | PULL | FULL
157 $map->{method} ||= 'checksum'; # | timestamp
158 $map->{source_exclude} ||= [qw( cs )];
159
160 # merge map to opts
161 map { $opts->{$_} = $map->{$_}; } keys %$map;
162
163 #print Dumper($opts);
164
165 # TODO: move this to checkOptions...
166
167 # check - do we have a target?
168 if (!$opts->{target_node}) {
169 $logger->warning( __PACKAGE__ . "->prepareOptions: No target given - please check metadata declaration.");
170 return;
171 }
172
173
174 #return $opts;
175 return 1;
176
177 }
178
179 sub prepareOptionsV2 {
180
181 my $self = shift;
182 my $opts = shift;
183
184 # patch options
185 $opts->{process}->{mode} ||= '';
186 $opts->{process}->{prepare} ||= 0;
187 $opts->{process}->{erase} ||= 0;
188
189 # pre-check options
190 if (!$self->_preCheckOptions($opts)) {
191 $logger->error( __PACKAGE__ . "->prepareOptionsV2: _preCheckOptions failed.");
192 return;
193 }
194
195 # inform user about option preparation
196 $logger->notice( __PACKAGE__ . "->prepareOptionsV2( source.node='$opts->{source}->{nodeName}', target.node='$opts->{target}->{nodeName}', mode='$opts->{process}->{mode}', e='$opts->{process}->{erase}', p='$opts->{process}->{prepare}' )");
197
198 # try to load mapping-metadata-container
199 #my $mapObject = getNewPerlObjectByPkgName($opts->{map}->{moduleName});
200 my $mapObject = DesignPattern::Object->fromPackage($opts->{map}->{moduleName});
201
202 # try to resolve map from metadata-container
203
204 # type of the item/node
205 my $source_nodeType = $opts->{source}->{nodeType};
206
207 # check if mapping for certain node is contained in mapping object
208 if (!$mapObject->can($source_nodeType)) {
209 $logger->warning( __PACKAGE__ . "->prepareOptionsV2: Can't access mapping for source-type=\"$source_nodeType\" - please check \"$opts->{map}->{moduleName}\".");
210 return;
211 }
212
213
214 # get map
215 my $map = $mapObject->$source_nodeType;
216 #print Dumper($map);
217
218 =pod
219 # check here if "target" is actually a CODEref - in this case: resolve it - deprecated!!! ???
220 if (ref $map->{target}->{address} eq 'CODE') {
221 $map->{target}->{address} = $map->{target}->{address}->($source_nodeType);
222 }
223
224 # resolve expressions (on nodename-level) here
225 if ($map->{target}->{address} =~ m/^(code|expr):(.+?)$/) {
226 my $target_dynamic_type = $1;
227 my $target_dynamic_expression = $2;
228 if (lc $target_dynamic_type eq 'code') {
229 $map->{target} = $mapObject->$target_dynamic_expression($map);
230 }
231 }
232 =cut
233
234 #map { $opts->{$_} = $map->{$_}; } keys %$map;
235 my $opts_merged = merge( $opts, $map );
236
237 $self->{options} = $opts_merged;
238 $self->{state}->{options_ready} = 1;
239
240 return 1;
241
242 }
243
244
245 sub configure {
246 my $self = shift;
247 my @args = @_;
248 if (!isEmpty(\@args)) {
249 my %properties = @_;
250 # merge args to properties
251 map { $self->{$_} = $properties{$_}; } keys %properties;
252 $self->_init();
253 $self->_initV1();
254 } else {
255 #print "no args!", "\n";
256 }
257 #print Dumper($self);
258 $self->{state}->{configured} = 1;
259 return 1;
260 }
261
262 sub configureV2 {
263 my $self = shift;
264 my @args = @_;
265 if (!isEmpty(\@args)) {
266 my %properties = @_;
267 # merge args to properties
268 #map { $self->{$_} = $properties{$_}; } keys %properties;
269 $self->{options} = merge($self->{options}, \%properties);
270 $self->_init();
271 #$self->_initV1();
272 } else {
273 #print "no args!", "\n";
274 }
275
276 #print Dumper($self);
277
278 $self->{state}->{configured} = 1;
279 return 1;
280 }
281
282 sub _getDirectedArrow {
283 my $self = shift;
284 my $mode = shift;
285 $mode ||= '';
286
287 if (lc $mode eq 'push') {
288 return '->';
289 } elsif (lc $mode eq 'pull') {
290 return '<-';
291 } elsif (lc $mode eq 'full') {
292 return '<->';
293 } else {
294 return '';
295 }
296 }
297
298 # TODO: some feature to show off the progress of synchronization (cur/max * 100)
299 sub syncNodes {
300
301 my $self = shift;
302 my $args = shift;
303
304 if (!$self->{state}->{configured}) {
305 $logger->critical( __PACKAGE__ . "->syncNodes: Synchronization object is not configured/initialized correctly." );
306 return;
307 }
308
309 # remember arguments through the whole processing
310 $self->{args} = $args;
311
312 $logger->debug( __PACKAGE__ . "->syncNodes: starting" );
313
314 # hash to hold and/or fill in metadata required for the processing
315 $self->{meta} = {};
316
317 # hash to sum up results
318 # TODO: re-implement! (sync-statistics???)
319
320 # detect synchronization method to determine which optical symbol (directed arrow) to use
321 my $mode = $self->{args}->{mode}; # V1
322 $mode ||= $self->{options}->{process}->{mode}; # V2
323 my $direction_arrow = $self->_getDirectedArrow($mode);
324
325 if (!$self->{options}->{metadata}->{version} || $self->{options}->{metadata}->{version} < 0.2) {
326 $self->_buildMetadataV1();
327 } else {
328 $self->_buildMetadataV2();
329 }
330
331 $logger->info( __PACKAGE__ . "->syncNodes: source=$self->{meta}->{source}->{dbKey}/$self->{meta}->{source}->{nodeName} [$self->{meta}->{source}->{nodeType}] $direction_arrow target=$self->{meta}->{target}->{dbKey}/$self->{meta}->{target}->{nodeName} [$self->{meta}->{target}->{nodeType}]" );
332
333 return if !$self->_buildFieldmappingV1();
334 return if !$self->_handleNodeContainers();
335 return if !$self->_prepareSync();
336
337 #print Dumper($self);
338 #print Dumper($self->{args});
339 #print Dumper($self->{options});
340 #print Dumper($self->{meta});
341 #print Dumper($self->{metadata});
342
343 $self->_syncNodes();
344
345 }
346
347
348 sub _handleNodeContainers {
349 my $self = shift;
350
351 # check partners/nodes: does partner exist / is node available?
352 foreach my $partner (keys %{$self->{meta}}) {
353
354 # 1. check partners & storages
355 if (!$self->{meta}->{$partner}) {
356 $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not find partner '$partner' in configuration metadata." );
357 next;
358 }
359
360 my $dbkey = $self->{meta}->{$partner}->{dbKey};
361
362 #print Dumper($self->{meta});
363
364 if (!$self->{meta}->{$partner}->{storage}) {
365 $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not access storage ( partner='$partner', dbKey='$dbkey' ) - configuration-error?" );
366 next;
367 }
368
369 # TODO:
370 # 2. check if partners (and nodes?) are actually available....
371 # eventually pre-check mode of access-attempt (read/write) here to provide an "early-croak" if possible
372
373 # print Dumper($self->{meta}->{$partner}->{storage}->{locator});
374
375 my $dbType = $self->{meta}->{$partner}->{storage}->{locator}->{type};
376 #print "dbType: $dbType", "\n";
377
378 # 3. check nodes
379 next if $dbType eq 'DBI'; # HACK for DBD::CSV - re-enable for others
380 # get node-name
381 # print Dumper($self);
382 #print Dumper($self->{meta}->{$partner});
383 #print "ΓΆΓΆ", $self->{meta}->{$partner}->{node}, "\n";
384 my $nodename = $self->{meta}->{$partner}->{node}; # V1
385 $nodename ||= $self->{meta}->{$partner}->{nodeName}; # V2
386 # check if nodename is actually a CODEref, execute it to get a mapped/filtered target-nodename
387
388 #print "nodename: $nodename", "\n";
389
390 $logger->debug( __PACKAGE__ . "->_handleNodeContainers: Accessing dbType=\"$dbType\", nodename=\"$nodename\"." );
391
392 =pod
393 #print "----", ref $nodename, "\n";
394 if ($nodename =~ m/CODE/) {
395 print Dumper($self);
396 #exit;
397 $nodename = $nodename->($nodename);
398 }
399 =cut
400
401 #print Dumper($self);
402
403 #print "partner: $partner - nodename: $nodename", "\n";
404
405 if (!$self->{meta}->{$partner}->{storage}->existsChildNode($nodename)) {
406 #print "ex", "\n";
407 #exit;
408
409 if ($partner eq 'target' && $self->{options}->{target}->{autocreateFolders}) {
410 if (!$self->{meta}->{$partner}->{storage}->createChildNode($nodename)) {
411 $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not create node '$self->{meta}->{$partner}->{nodeName}\@$self->{meta}->{$partner}->{dbKey}' [$self->{meta}->{$partner}->{nodeType}]." );
412 next;
413 }
414 } else {
415 $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not reach node \"$nodename\" at partner \"$partner\"." );
416 next;
417 }
418 }
419
420 }
421
422 return 1;
423
424 }
425
426
427 sub _prepareSync {
428 my $self = shift;
429
430 # TODO:
431 # + if action == PUSH: start processing
432 # -+ if action == PULL: swap metadata and start processing
433 # - if action == FULL: start processing, then swap metadata and (re-)start processing
434
435 # manipulate metainfo according to direction of synchronization
436 if (lc $self->{args}->{direction} eq 'push') {
437 # just do it ...
438 } elsif (lc $self->{args}->{direction} eq 'pull') {
439 #print "=======SWAP", "\n";
440 # swap
441 ($self->{meta}->{source}, $self->{meta}->{target}) =
442 ($self->{meta}->{target}, $self->{meta}->{source});
443 } elsif (lc $self->{args}->{direction} eq 'full') {
444 } else {
445 }
446
447 # import flag means: prepare the source node to be syncable
448 # this is useful if there are e.g. no "ident" or "checksum" columns yet inside a DBI like (row-based) storage
449 if ($self->{args}->{prepare}) {
450 $self->_prepareNode_MetaProperties('source');
451 $self->_prepareNode_DummyIdent('source');
452 #return;
453 #$self->_erase_all($opts->{source_node});
454 }
455
456 # erase flag means: erase the target
457 #if ($opts->{erase}) {
458 if ($self->{args}->{erase}) {
459 # TODO: move this method to the scope of the synchronization core and wrap it around different handlers
460 #print "ERASE", "\n";
461 $self->_erase_all('target');
462 }
463
464 return 1;
465
466 }
467
468 1;

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