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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (hide 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 joko 1.2 ## $Id: API.pm,v 1.1 2003/01/19 01:23:04 joko Exp $
2 joko 1.1 ##
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 joko 1.2 ## $Log: API.pm,v $
9     ## Revision 1.1 2003/01/19 01:23:04 joko
10     ## + new from Data/Transfer/Sync.pm
11     ##
12 joko 1.1 ## ----------------------------------------------------------------------------------------
13    
14    
15 joko 1.2 package Data::Transfer::Sync::API;
16    
17 joko 1.1 use strict;
18     use warnings;
19 joko 1.2
20 joko 1.1 use mixin::with qw( Data::Transfer::Sync );
21 joko 1.2
22 joko 1.1
23     # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - main
24 joko 1.2
25     use Data::Dumper;
26    
27 joko 1.1 use Data::Compare::Struct qw( getDifference isEmpty );
28     use Data::Transform::Deep qw( merge );
29 joko 1.2
30 joko 1.1 # get logger instance
31     my $logger = Log::Dispatch::Config->instance;
32 joko 1.2
33 joko 1.1 sub _init {
34     my $self = shift;
35     }
36 joko 1.2
37 joko 1.1 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 joko 1.2
59 joko 1.1 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 joko 1.2
85 joko 1.1 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 joko 1.2
179 joko 1.1 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 joko 1.2 $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 joko 1.1
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 joko 1.2
244    
245 joko 1.1 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 joko 1.2
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 joko 1.1 # 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 joko 1.2 # TODO: re-implement! (sync-statistics???)
319 joko 1.1
320     # detect synchronization method to determine which optical symbol (directed arrow) to use
321 joko 1.2 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 joko 1.1 } else {
328 joko 1.2 $self->_buildMetadataV2();
329 joko 1.1 }
330    
331 joko 1.2 $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 joko 1.1
333 joko 1.2 return if !$self->_buildFieldmappingV1();
334     return if !$self->_handleNodeContainers();
335     return if !$self->_prepareSync();
336 joko 1.1
337     #print Dumper($self);
338 joko 1.2 #print Dumper($self->{args});
339     #print Dumper($self->{options});
340 joko 1.1 #print Dumper($self->{meta});
341 joko 1.2 #print Dumper($self->{metadata});
342    
343     $self->_syncNodes();
344    
345     }
346 joko 1.1
347    
348 joko 1.2 sub _handleNodeContainers {
349     my $self = shift;
350 joko 1.1
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 joko 1.2 $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not find partner '$partner' in configuration metadata." );
357     next;
358 joko 1.1 }
359    
360 joko 1.2 my $dbkey = $self->{meta}->{$partner}->{dbKey};
361 joko 1.1
362     #print Dumper($self->{meta});
363    
364     if (!$self->{meta}->{$partner}->{storage}) {
365 joko 1.2 $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not access storage ( partner='$partner', dbKey='$dbkey' ) - configuration-error?" );
366     next;
367 joko 1.1 }
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 joko 1.2 my $nodename = $self->{meta}->{$partner}->{node}; # V1
385     $nodename ||= $self->{meta}->{$partner}->{nodeName}; # V2
386 joko 1.1 # check if nodename is actually a CODEref, execute it to get a mapped/filtered target-nodename
387    
388     #print "nodename: $nodename", "\n";
389    
390 joko 1.2 $logger->debug( __PACKAGE__ . "->_handleNodeContainers: Accessing dbType=\"$dbType\", nodename=\"$nodename\"." );
391 joko 1.1
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 joko 1.2
401     #print Dumper($self);
402    
403     #print "partner: $partner - nodename: $nodename", "\n";
404 joko 1.1
405     if (!$self->{meta}->{$partner}->{storage}->existsChildNode($nodename)) {
406 joko 1.2 #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 joko 1.1 }
419    
420     }
421 joko 1.2
422     return 1;
423    
424     }
425    
426    
427     sub _prepareSync {
428     my $self = shift;
429 joko 1.1
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 joko 1.2
464     return 1;
465 joko 1.1
466     }
467    
468     1;

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