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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by joko, Mon Jan 20 16:59:48 2003 UTC revision 1.8 by joko, Thu Mar 27 15:31:15 2003 UTC
# Line 6  Line 6 
6  ##  ##
7  ##    ----------------------------------------------------------------------------------------  ##    ----------------------------------------------------------------------------------------
8  ##    $Log$  ##    $Log$
9    ##    Revision 1.8  2003/03/27 15:31:15  joko
10    ##    fixes to modules regarding new namespace(s) below Data::Mungle::*
11    ##
12    ##    Revision 1.7  2003/02/21 08:00:24  joko
13    ##    debugging
14    ##
15    ##    Revision 1.6  2003/02/14 12:58:47  joko
16    ##    + re-enabled the erase-mechanism
17    ##
18    ##    Revision 1.5  2003/02/11 05:26:04  joko
19    ##    + sub _tellWhatIWillDo
20    ##    + re-enabled "branch to execution path for special targets" mechanism
21    ##
22    ##    Revision 1.4  2003/02/09 05:03:02  joko
23    ##    + minor fix regarding namespace of api versioning extension module
24    ##
25    ##    Revision 1.3  2003/02/09 04:59:27  joko
26    ##    + api versioning mechanism
27    ##    + major structure changes
28    ##    - refactored code to sister modules
29    ##
30  ##    Revision 1.2  2003/01/20 16:59:48  joko  ##    Revision 1.2  2003/01/20 16:59:48  joko
31  ##    + cosmetics and debugging  ##    + cosmetics and debugging
32  ##  ##
# Line 20  package Data::Transfer::Sync::API; Line 41  package Data::Transfer::Sync::API;
41  use strict;  use strict;
42  use warnings;  use warnings;
43    
44    use base qw( DesignPattern::Bridge );
45    
46  use mixin::with qw( Data::Transfer::Sync );  use mixin::with qw( Data::Transfer::Sync );
47    
48    
49  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -   main  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -   main
50    
51  use Data::Dumper;  use Data::Dumper;
52    use Hash::Merge qw( merge );
53    
54  use Data::Compare::Struct qw( getDifference isEmpty );  use Data::Mungle::Compare::Struct qw( isEmpty );
 use Data::Transform::Deep qw( merge );  
55    
56  # get logger instance  # get logger instance
57  my $logger = Log::Dispatch::Config->instance;  my $logger = Log::Dispatch::Config->instance;
58    
59  sub _init {  
60    sub api_constructor {
61    my $self = shift;    my $self = shift;
62      $logger->debug( __PACKAGE__ . "->api_constructor: Loading API");
63      $self->_loadVersionExtensions();
64  }  }
65    
 sub checkOptions {  
   my $self = shift;  
   my $opts = shift;  
     
   my $result = 1;  
     
   # check - do we have a target node?  
   if (!$opts->{target_node}) {  
     $logger->warning( __PACKAGE__ . "->checkOptions: Error while resolving resource metadata - no 'target node' could be determined.");  
     $result = 0;  
   }  
66    
67    # check - do we have a mapping?  sub _loadVersionExtensions {
68    if (!$opts->{mapping} && !$opts->{mapping_module}) {    my $self = shift;
69      $logger->warning( __PACKAGE__ . "->checkOptions: Error while resolving resource metadata - no 'mapping' could be determined.");    my $syncVersion = $self->{sync_version};
70      $result = 0;    $syncVersion ||= '';
71    }    $logger->debug( __PACKAGE__ . "->loadVersionExtensions( version='$syncVersion' )");
72        #print Dumper($self);
73    return $result;    #exit;
74        my $module = "API::$syncVersion";
75      $self->load($module);
76  }  }
77    
78  sub checkOptionsV2 {  
79    sub configure {
80    my $self = shift;    my $self = shift;
81    
82  #print Dumper($self->{options});    $logger->debug( __PACKAGE__ . "->configure");
83    
84    my $result = 1;    my @args = @_;
85    
86    # check - do we have a target node?    if (!isEmpty(\@args)) {
87    if (!$self->{options}->{target}->{nodeName}) {      my %properties = @_;
88      $logger->warning( __PACKAGE__ . "->checkOptionsV2: No target given - please check metadata declaration.");      # merge args to properties
89      $result = 0;      #map { $self->{$_} = $properties{$_}; } keys %properties;
90    }  #print Dumper($self);
91      #print Dumper(\%properties);
92    # check - do we have a mapping?      if ($self->{options}) {
93    if (!$self->{options}->{fieldmap}) {      my $options_new = merge($self->{options}, \%properties);
94      $logger->warning( __PACKAGE__ . "->checkOptionsV2: Error while resolving resource metadata - no 'fieldmap' could be determined.");  #print Dumper($options_new);
95      $result = 0;      $self->{options} = $options_new;
96    #print Dumper($self->{options});
97        } else {
98          $self->{options} = \%properties;
99        }
100        $self->_init();
101        #$self->_initV1();
102      } else {
103        #print "no args!", "\n";
104    }    }
     
   # TODO: extend!  
105    
106    return $result;  #print Dumper($self);
107    #exit;
108    
109      $self->{state}->{configured} = 1;
110      return 1;
111  }  }
112    
113    
114  sub prepareOptions {  sub setArguments {
115      my $self = shift;
116      my $args_raw = shift;
117      $self->{args_raw} = $args_raw;
118    }
119    
120    sub readArguments {
121    my $self = shift;    my $self = shift;
   my $opts = shift;  
122    
123  #print Dumper($opts);      my %syncConfig;
124        tie %syncConfig, 'Tie::IxHash';
125        %syncConfig = (
126          map => {
127            moduleName => $self->{args_raw}->{'mapping-module'},
128          },
129          source => {
130            dbKey => $self->{args_raw}->{source},
131            nodeType => $self->{args_raw}->{'source-type'},
132            nodeName => $self->{args_raw}->{'source-node'},
133          },
134          target => {
135            dbKey => $self->{args_raw}->{target},
136            nodeName => $self->{args_raw}->{'target-node'},
137          },
138          process => {
139            mode => $self->{args_raw}->{mode},
140            erase => $self->{args_raw}->{erase},
141            import => $self->{args_raw}->{import},
142            prepare => $self->{args_raw}->{prepare},
143          },
144    #      metadata => {
145    #        config => $self->{config_metadata},
146    #      }
147        );
148    
149      $self->{args} = \%syncConfig;
150    
151    }
152    
153    
154    # TODO: some feature to show off the progress of synchronization (cur/max * 100)
155    sub syncNodes {
156    
157      my $self = shift;
158      my $args = shift;
159    
160      #$logger->notice( "==========================   " . __PACKAGE__ . "->syncNodes   ==============");
161      $logger->debug( __PACKAGE__ . "->syncNodes: starting" );
162    
163    #print Dumper($self);
164  #exit;  #exit;
165    
166    $opts->{mode} ||= '';  #print Dumper($self->{options});
167    $opts->{erase} ||= 0;    $self->_prepareOptions();
   $opts->{prepare} ||= 0;  
   #$opts->{import} ||= 0;  
     
   if (!$opts->{source_node}) {  
     $logger->error( __PACKAGE__ . "->prepareOptions failed: Please specify source-node!");  
     return;  
   }  
     
   $logger->notice( __PACKAGE__ . "->prepareOptions( source_node $opts->{source_node} mode $opts->{mode} erase $opts->{erase} prepare $opts->{prepare} )");  
168    
169    #if (!$opts->{mapping} || !$opts->{mapping_module}) {    # trace
170    if (!$opts->{mapping}) {      #print Dumper($self->{options});
171      $logger->warning( __PACKAGE__ . "->prepareOptions: No mapping supplied - please check key 'mappings' in global configuration or specify additional argument '--mapping'.");      #exit;
     #return;  
   }  
172    
173    $opts->{mapping_module} ||= $opts->{mapping};    if (!$self->checkOptions()) {
174    my $evstring = "use $opts->{mapping_module};";      $logger->critical( __PACKAGE__ . "->syncNodes: 'Data::Transfer::Sync::checkOptions' failed.");
   eval($evstring);  
   if ($@) {  
     $logger->warning( __PACKAGE__ . "->prepareOptions: error while trying to access mapping - $@");  
175      return;      return;
176    }    }
177    
178    # resolve mapping metadata (returned from sub)    if (!$self->{state}->{configured}) {
179    my $mapObject = $opts->{mapping_module}->new();      $logger->critical( __PACKAGE__ . "->syncNodes: Synchronization object is not configured/initialized correctly." );
   #print Dumper($map);  
   my $source_node_name = $opts->{source_node};  
   # check if mapping for certain node is contained in mapping object  
   if (!$mapObject->can($source_node_name)) {  
     $logger->warning( __PACKAGE__ . "->prepareOptions: Can't access mapping for node \"$source_node_name\" - please check $opts->{mapping_module}.");  
180      return;      return;
181    }    }
   my $map = $mapObject->$source_node_name;  
182    
183  #print Dumper($map);    #print Dumper($args);
184    
185    # check here if "target" is actually a CODEref - in this case: resolve it - deprecated!!! ???    # remember arguments through the whole processing
186    if (ref $map->{target} eq 'CODE') {    $self->{args} = $args;
187      $map->{target} = $map->{target}->($source_node_name);  
188    }    # hash to hold and/or fill in metadata required for the processing
189      $self->{meta} = {};
190        
191    # resolve expressions (on nodename-level) here    # hash to sum up results
192    if ($map->{target} =~ m/^(code|expr):(.+?)$/) {    # TODO: re-implement! (sync-statistics???)
193      my $target_dynamic_type = $1;  
194      my $target_dynamic_expression = $2;    #print Dumper($self->{options}->{process});
195      if (lc $target_dynamic_type eq 'code') {  
196  #      $map->{target} = $mapObject->$target_dynamic_expression($map);    # detect synchronization method to determine which optical symbol (directed arrow) to use
197      my $mode = $self->{args}->{mode};   # V1
198      $mode ||= $self->{options}->{process}->{mode};    # V2
199      my $direction_arrow = $self->_getDirectedArrow($mode);
200    
201      # determine code versions
202        my $code_metadata_version;
203        # first, try to use version supplied by mapping-metadata
204        $code_metadata_version = $self->{options}->{metadata}->{version};
205        # if not set, inherit from global 'sync_version'
206        $code_metadata_version ||= $self->{sync_version};
207    
208      # load additional code from versioned namespace into current instance
209        my $dynModule = "Metadata::$code_metadata_version";
210        $self->load($dynModule);
211        
212      # build metadata using versioned code and stuff
213        $self->options2metadata();
214        $self->options2metadata_accessor();
215    
216      # branch to execution path for special targets
217      # detect for option 'handler' which could be a CODEref
218        if ($self->{options}->{handler} && ref $self->{options}->{handler} eq 'CODE') {
219          $logger->info( __PACKAGE__ . "->syncNodes: Running (special handler code - no generic sync!) on '$self->{options}->{target}->{dbKey}' with MODE $self->{options}->{process}->{mode}, NODE $self->{options}->{target}->{address}");
220          #print Dumper($self);
221          #exit;
222          # don't do this any more - it wasn't very nice somehow ...
223          #$self->{options}->{handler}->($self->{app}, $self->{options});
224          # .... now: better let the parent application scope handle this via callback
225            # not any more required for this: $self->{app} inside here (which isn't the app we mean here)
226            # required for this: getting the options out of here: establish some getter method! ($self->getOptions(...))
227            # so....
228            #$self->{__bridge}->{parent_ref}->
229          
230          # ahh okay, DesignPattern::Bridge moves closer to some Class::Inner!???
231            # so...
232            # similar like above - but it isn't very nice anyway ...  (no privateness, but: who cares?)
233            #print Dumper($self->{__bridge});
234            # just take the global application instance and
235            # throw it into the context of the mapping module - this is heavy!  ;-) (but again, who cares...)
236            # TODO: handle this more abstract *sometime*
237            #$self->{options}->{handler}->($self->{__bridge}->{parent}->{app}, $self->{options});
238            $self->{options}->{handler}->($self->{__bridge}->{parent}->{process}, $self->{options});
239          
240          return;
241      }      }
   }  
242    
243    # remove asymmetries from $map (patch keys)    # TODO: execution path branch V2!!!
244    $map->{source_node} = $map->{source}; delete $map->{source};      # option1: wrap this via callback to parent scope (like current impl. mechanism)
245    $map->{target_node} = $map->{target}; delete $map->{target};      # option2: branch directly from here (this needs refactoring of the sub handler)
   $map->{mapping} = $map->{details}; delete $map->{details};  
   $map->{direction} = $map->{mode}; delete $map->{mode};  
   
   # defaults (mostly for backward-compatibility)  
   $map->{source_node} ||= $source_node_name;  
   $map->{source_ident} ||= 'storage_method:id';  
   $map->{target_ident} ||= 'property:oid';  
   $map->{direction} ||= $opts->{mode};         # | PUSH | PULL | FULL  
   $map->{method} ||= 'checksum';                # | timestamp  
   $map->{source_exclude} ||= [qw( cs )];  
246    
247    # merge map to opts    # tracing
248    map { $opts->{$_} = $map->{$_}; } keys %$map;      #print Dumper($self);
249            #exit;
 #print Dumper($opts);  
250    
251    # TODO: move this to checkOptions...    # V1:
252      $logger->debug( __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}]" );
253        
254    # check - do we have a target?    # V2:
255    if (!$opts->{target_node}) {    my $what = "$self->{meta}->{source}->{dbKey}/$self->{meta}->{source}->{nodeName} [$self->{meta}->{source}->{nodeType}] $direction_arrow $self->{meta}->{target}->{dbKey}/$self->{meta}->{target}->{nodeName} [$self->{meta}->{target}->{nodeType}]";
256      $logger->warning( __PACKAGE__ . "->prepareOptions: No target given - please check metadata declaration.");    #my $header = ("~.." x 7) . "  " . $what . "  " . ("~.." x 4);
257      return;    #my $header = ("= " x 7) . "  " . $what . "  " . ("= " x 4);
258    }    #my $header = ("~=-_-=" x 3) . "  " . $what . "  " . ("~=-_-=" x 4);
259      my $header = ("_-=~=-" x 4) . "  " . $what . "  " . ("_-=~=-" x 4);
260      $logger->notice($header);
261    
262    
263    #return $opts;    return if !$self->buildFieldmapping();
264    return 1;    return if !$self->_touchNodeSet();
265      return if !$self->_prepare_sync();
266      $self->_tellWhatIWillDo();
267    
268      # tracing
269        #print Dumper($self);
270        #print Dumper($self->{args});
271        #print Dumper($self->{options});
272        #print Dumper($self->{meta});
273        #print Dumper($self->{metadata});
274        #exit;
275    
276      # finally, tell the core to start the synchronization process
277      $self->_run();
278      
279  }  }
280    
 sub prepareOptionsV2 {  
281    
282    my $c_string_default = '';
283    sub c_string {
284      my $value = shift;
285      $value ||= "[$c_string_default]";
286      return $value;
287    }
288    
289    sub _tellWhatIWillDo {
290    my $self = shift;    my $self = shift;
291    my $opts = shift;  
292    
293    #return;
294      
295      # trace
296        #print Dumper($self->{meta});
297        #exit;
298      
299      $c_string_default = 'n/a';
300      my $source = c_string($self->{opt}->{'source'});
301      my $source_node = c_string($self->{opt}->{'source-node'});
302      my $source_type = c_string($self->{opt}->{'source-type'});
303      my $target = c_string($self->{opt}->{'target'});
304      my $target_node = c_string($self->{opt}->{'target-node'});
305      my $target_type = c_string($self->{opt}->{'target-type'});
306      
307      my $mapping_module = c_string($self->{opt}->{'mapping-module'});
308      my $mode = uc c_string($self->{opt}->{'mode'});
309    
310      #my $ql = "$mode INTO $source NODE $source_node TYPE $source_type SELECT NODE $target_node TYPE $target_type FROM $target USING MODULE $mapping_module;";
311      #$logger->notice( __PACKAGE__ . ": $ql" );
312      my $ql = <<EOT;
313    
314      FETCH DATA
315        FROM STORAGE $self->{meta}->{source}->{dbKey}
316        AT NODE $self->{meta}->{source}->{accessorName}.$self->{meta}->{source}->{nodeName}
317        USING IDENTIFIER $self->{meta}->{source}->{IdentProvider}->{method}.$self->{meta}->{source}->{IdentProvider}->{arg}
318      CONVERT DATA
319        CAST FROM $self->{meta}->{source}->{nodeType} TO $self->{meta}->{target}->{nodeType}
320        MAP ATTRIBUTES FROM @{$self->{meta}->{source}->{childnodes}} TO @{$self->{meta}->{target}->{childnodes}}
321      STORE DATA
322        TO STORAGE $self->{meta}->{target}->{dbKey}
323        AT NODE $self->{meta}->{target}->{accessorName}.$self->{meta}->{target}->{nodeName}
324        USING IDENTIFIER $self->{meta}->{target}->{IdentProvider}->{method}.$self->{meta}->{target}->{IdentProvider}->{arg}
325    EOT
326      
327      
328      chomp($ql);
329      $logger->info($ql);
330      
331      #exit;
332      return;
333      
334      my $actioning = ucfirst $self->{opt}->{'action'} . 'ing';
335      
336      # FIXME: this is weird!
337      my $long = <<EOT;
338    
339        - $actioning data of type $target_type and
340          filtered by $target_node from the storage named $target
341          to the storage named $source - filtered by $source_node.
342        - Will attempt to convert the data to $source_type.
343    EOT
344      chomp($long);
345      $logger->notice( __PACKAGE__ . ": $long" );
346      
347    }
348    
349    
350    sub _prepareOptions {
351    
352      my $self = shift;
353      
354      my $opts = $self->{args};
355    
356    # patch options    # patch options
357        $opts->{source}->{nodeName} ||= '';
358        $opts->{target}->{nodeName} ||= '';
359      $opts->{process}->{mode} ||= '';      $opts->{process}->{mode} ||= '';
     $opts->{process}->{prepare} ||= 0;  
360      $opts->{process}->{erase} ||= 0;      $opts->{process}->{erase} ||= 0;
361        $opts->{process}->{prepare} ||= 0;
362    
363      # defaults (mostly for backward-compatibility to V1 -
364      # but code mungled here out of prepareOptions_V1 from Version::V1)
365        $opts->{metadata}->{syncMethod} ||= 'checksum';                # | timestamp
366        $opts->{source}->{ident} ||= 'storage_method:id';
367        $opts->{source}->{exclude} ||= [qw( cs )];
368        $opts->{target}->{ident} ||= 'property:oid';
369        #$map->{source_node} ||= $source_node_name;
370        #$map->{direction} ||= $opts->{mode};         # | PUSH | PULL | FULL
371    
372    # pre-check options    # pre-check options
373      if (!$self->_preCheckOptions($opts)) {      if (!$self->_preCheckOptions($opts)) {
374        $logger->error( __PACKAGE__ . "->prepareOptionsV2: _preCheckOptions failed.");        $logger->error( __PACKAGE__ . "->_prepareOptions: _preCheckOptions failed.");
375        return;        return;
376      }      }
377    
378    # inform user about option preparation    # inform user about option preparation
379    $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}' )");    $logger->debug( __PACKAGE__ . "->_prepareOptions( source.node='$opts->{source}->{nodeName}', target.node='$opts->{target}->{nodeName}', mode='$opts->{process}->{mode}', e='$opts->{process}->{erase}', p='$opts->{process}->{prepare}' )");
380    
381    # try to load mapping-metadata-container    # try to load mapping-metadata-container
382    #my $mapObject = getNewPerlObjectByPkgName($opts->{map}->{moduleName});      # How? Create a new instance of the given
383    my $mapObject = DesignPattern::Object->fromPackage($opts->{map}->{moduleName});      # perl module/package name in ->{...}->{moduleName}.
384        # This instance is used later in the innards of the sync,
385        # that's why the module (class) should have a certain layout
386        # enabling the core to use it for gathering metadata while processing.
387        my $mapObject = DesignPattern::Object->fromPackage($opts->{map}->{moduleName});
388    
389    # try to resolve map from metadata-container    # try to resolve map from metadata-container
390    
# Line 208  sub prepareOptionsV2 { Line 392  sub prepareOptionsV2 {
392      my $source_nodeType = $opts->{source}->{nodeType};      my $source_nodeType = $opts->{source}->{nodeType};
393            
394      # check if mapping for certain node is contained in mapping object      # check if mapping for certain node is contained in mapping object
395      if (!$mapObject->can($source_nodeType)) {      if (!$mapObject || !$mapObject->can($source_nodeType)) {
396        $logger->warning( __PACKAGE__ . "->prepareOptionsV2: Can't access mapping for source-type=\"$source_nodeType\" - please check \"$opts->{map}->{moduleName}\".");        $logger->warning( __PACKAGE__ . "->_prepareOptions: Can't access mapping for source-type=\"$source_nodeType\" - please check \"$opts->{map}->{moduleName}\".");
397        return;        return;
398      }      }
399    
   
400      # get map      # get map
401      my $map = $mapObject->$source_nodeType;      my $map = $mapObject->$source_nodeType;
402      #print Dumper($map);      #print Dumper($map);
403        
404  =pod        my $map_version = $map->{metadata}->{version};
405        # FIXME: backward compatibility
406        if (!$map_version) {
407          $self->options_to_V2($map);
408        }
409    
410        # trace
411          #print Dumper($map);
412          #exit;
413          #print "ref: ", ref $map->{target}, "\n";
414          #print "target: ", $map->{target}, "\n";
415        
416      # check here if "target" is actually a CODEref - in this case: resolve it - deprecated!!! ???      # check here if "target" is actually a CODEref - in this case: resolve it - deprecated!!! ???
417      if (ref $map->{target}->{address} eq 'CODE') {      if (ref $map->{target}->{address} eq 'CODE') {
418        $map->{target}->{address} = $map->{target}->{address}->($source_nodeType);        $map->{target}->{address} = $map->{target}->{address}->($source_nodeType);
419      }      }
420            
421      # resolve expressions (on nodename-level) here      # resolve expressions (on nodename-level) here
422      if ($map->{target}->{address} =~ m/^(code|expr):(.+?)$/) {      elsif ($map->{target}->{address} =~ m/^(code|expr):(.+?)$/) {
423        my $target_dynamic_type = $1;        my $target_dynamic_type = $1;
424        my $target_dynamic_expression = $2;        my $target_dynamic_expression = $2;
425        if (lc $target_dynamic_type eq 'code') {        if (lc $target_dynamic_type eq 'code') {
426          $map->{target} = $mapObject->$target_dynamic_expression($map);          $map->{target} = $mapObject->$target_dynamic_expression($map);
427        }        }
428      }      }
 =cut  
429    
430    #map { $opts->{$_} = $map->{$_}; } keys %$map;    # merging - V1
431    my $opts_merged = merge( $opts, $map );      #map { $opts->{$_} = $map->{$_}; } keys %$map;
432        # trace
433          #print Dumper($self->{options});
434      
435      # merging - V2
436    
437        # merge local map with local opts
438        
439          # delete undef'd items in $map
440        
441          # enable cloning
442          # FIXME: do we really need cloning here? trade safety/encapsulation for speed?
443          Hash::Merge::set_clone_behavior(1);
444          Hash::Merge::set_behavior( 'RIGHT_PRECEDENT' );
445          #Hash::Merge::set_behavior( 'STORAGE_PRECEDENT' );
446          #Hash::Merge::set_behavior( 'RETAINMENT_PRECEDENT' );
447          # TODO: add an option to Hash::Merge not to overwrite set items with undefined/empty/not assigned ones
448          my $locals_merged = merge( $opts, $map );
449    
450        # trace
451          #print Dumper($opts);
452          #print Dumper($map);
453          #print Dumper($locals_merged);
454          #exit;
455    
456        # merge local-merged ones with instance-wide options
457          Hash::Merge::set_clone_behavior(0);
458          $self->{options} = merge( $self->{options}, $locals_merged );
459      
460        # trace
461          #print Dumper($self->{options});
462          #exit;
463      
464    
   $self->{options} = $opts_merged;  
465    $self->{state}->{options_ready} = 1;    $self->{state}->{options_ready} = 1;
466    
467    return 1;    return 1;
# Line 245  sub prepareOptionsV2 { Line 469  sub prepareOptionsV2 {
469  }  }
470    
471    
472  sub configure {  sub _preCheckOptions {
   my $self = shift;  
   my @args = @_;  
   if (!isEmpty(\@args)) {  
     my %properties = @_;  
     # merge args to properties  
     map { $self->{$_} = $properties{$_}; } keys %properties;  
     $self->_init();  
     $self->_initV1();  
   } else {  
     #print "no args!", "\n";  
   }  
   #print Dumper($self);  
   $self->{state}->{configured} = 1;  
   return 1;  
 }  
473    
 sub configureV2 {  
474    my $self = shift;    my $self = shift;
475    my @args = @_;    my $opts = shift;
   if (!isEmpty(\@args)) {  
     my %properties = @_;  
     # merge args to properties  
     #map { $self->{$_} = $properties{$_}; } keys %properties;  
     $self->{options} = merge($self->{options}, \%properties);  
     $self->_init();  
     #$self->_initV1();  
   } else {  
     #print "no args!", "\n";  
   }  
   
 #print Dumper($self);  
   
   $self->{state}->{configured} = 1;  
   return 1;  
 }  
476    
477  sub _getDirectedArrow {    # trace
478    my $self = shift;      #print Dumper($opts);
479    my $mode = shift;      #exit;
480    $mode ||= '';      
481        if (!$opts->{process}->{mode}) {
482    if (lc $mode eq 'push') {      $logger->error( __PACKAGE__ . "->_preCheckOptions failed: Please specify \"--action=(load|save)\".");
483      return '->';      return;
   } elsif (lc $mode eq 'pull') {  
     return '<-';  
   } elsif (lc $mode eq 'full') {  
     return '<->';  
   } else {  
     return '';  
484    }    }
 }  
485    
486  # TODO: some feature to show off the progress of synchronization (cur/max * 100)    # the type of the to-be-synced item
487  sub syncNodes {    if (!$opts->{source}->{nodeType}) {
488        $logger->error( __PACKAGE__ . "->_preCheckOptions failed: Please specify \"source-type\".");
   my $self = shift;  
   my $args = shift;  
   
   if (!$self->{state}->{configured}) {  
     $logger->critical( __PACKAGE__ . "->syncNodes: Synchronization object is not configured/initialized correctly." );  
489      return;      return;
490    }    }
491      # the name of the (container-) node the items are listed in
492    # remember arguments through the whole processing    if (!$opts->{source}->{nodeName}) {
493    $self->{args} = $args;      $logger->error( __PACKAGE__ . "->_preCheckOptions failed: Please specify \"source-node\".");
494        return;
   $logger->debug( __PACKAGE__ . "->syncNodes: starting" );  
   
   # hash to hold and/or fill in metadata required for the processing  
   $self->{meta} = {};  
     
   # hash to sum up results  
   # TODO: re-implement! (sync-statistics???)  
   
   # detect synchronization method to determine which optical symbol (directed arrow) to use  
   my $mode = $self->{args}->{mode};   # V1  
   $mode ||= $self->{options}->{process}->{mode};    # V2  
   my $direction_arrow = $self->_getDirectedArrow($mode);  
   
   if (!$self->{options}->{metadata}->{version} || $self->{options}->{metadata}->{version} < 0.2) {  
     $self->_buildMetadataV1();  
   } else {  
     $self->_buildMetadataV2();  
495    }    }
496    
497    $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}]" );    # a "map"-declaration which module to use for mapping- and/or lookup-purposes
498      if (!$opts->{map}) {
499    return if !$self->_buildFieldmappingV1();      $logger->warning( __PACKAGE__ . "->_preCheckOptions: No mapping supplied - please check key 'map|mappings' in global configuration or specify additional argument '--mapping-module'.");
500    return if !$self->_handleNodeContainers();      return;
501    return if !$self->_prepareSync();    }
502      if (!$opts->{map}->{moduleName}) {
503        $logger->warning( __PACKAGE__ . "->_preCheckOptions: Currently only perl-modules can provide mappings: Please specify one with '--mapping-module=My::Mapping::Module'.");
504        return;
505      }
506    
507  #print Dumper($self);    return 1;
 #print Dumper($self->{args});  
 #print Dumper($self->{options});  
 #print Dumper($self->{meta});  
 #print Dumper($self->{metadata});  
508    
   $self->_syncNodes();  
     
509  }  }
510    
511    
 sub _handleNodeContainers {  
   my $self = shift;  
   
   # check partners/nodes: does partner exist / is node available?  
   foreach my $partner (keys %{$self->{meta}}) {  
       
     # 1. check partners & storages  
     if (!$self->{meta}->{$partner}) {  
       $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not find partner '$partner' in configuration metadata." );  
       next;  
     }  
   
     my $dbkey = $self->{meta}->{$partner}->{dbKey};  
   
 #print Dumper($self->{meta});  
512    
513      if (!$self->{meta}->{$partner}->{storage}) {  sub _prepare_sync {
       $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not access storage ( partner='$partner', dbKey='$dbkey' ) - configuration-error?" );  
       next;  
     }  
       
     # TODO:  
     # 2. check if partners (and nodes?) are actually available....  
     # eventually pre-check mode of access-attempt (read/write) here to provide an "early-croak" if possible  
       
 #    print Dumper($self->{meta}->{$partner}->{storage}->{locator});  
     
     my $dbType = $self->{meta}->{$partner}->{storage}->{locator}->{type};  
 #print "dbType: $dbType", "\n";  
       
     # 3. check nodes  
     next if $dbType eq 'DBI';    # HACK for DBD::CSV - re-enable for others  
     # get node-name  
 #      print Dumper($self);  
     #print Dumper($self->{meta}->{$partner});  
     #print "öö", $self->{meta}->{$partner}->{node}, "\n";  
     my $nodename = $self->{meta}->{$partner}->{node};   # V1  
     $nodename ||= $self->{meta}->{$partner}->{nodeName};    # V2  
     # check if nodename is actually a CODEref, execute it to get a mapped/filtered target-nodename  
   
 #print "nodename: $nodename", "\n";  
   
     $logger->debug( __PACKAGE__ . "->_handleNodeContainers: Accessing dbType=\"$dbType\", nodename=\"$nodename\"." );  
       
 =pod  
     #print "----", ref $nodename, "\n";  
     if ($nodename =~ m/CODE/) {  
       print Dumper($self);  
       #exit;  
       $nodename = $nodename->($nodename);  
     }  
 =cut      
   
 #print Dumper($self);  
       
     #print "partner: $partner - nodename: $nodename", "\n";  
       
     if (!$self->{meta}->{$partner}->{storage}->existsChildNode($nodename)) {  
 #print "ex", "\n";  
 #exit;  
514    
       if ($partner eq 'target' && $self->{options}->{target}->{autocreateFolders}) {  
         if (!$self->{meta}->{$partner}->{storage}->createChildNode($nodename)) {  
           $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not create node '$self->{meta}->{$partner}->{nodeName}\@$self->{meta}->{$partner}->{dbKey}' [$self->{meta}->{$partner}->{nodeType}]." );  
           next;  
         }  
       } else {  
         $logger->critical( __PACKAGE__ . "->_handleNodeContainers: Could not reach node \"$nodename\" at partner \"$partner\"." );  
         next;  
       }  
     }  
       
   }  
     
   return 1;  
   
 }  
   
   
 sub _prepareSync {  
515    my $self = shift;    my $self = shift;
516    
517    # TODO:    # TODO:
# Line 435  sub _prepareSync { Line 519  sub _prepareSync {
519    #  -+  if action == PULL: swap metadata and start processing    #  -+  if action == PULL: swap metadata and start processing
520    #   -  if action == FULL: start processing, then swap metadata and (re-)start processing    #   -  if action == FULL: start processing, then swap metadata and (re-)start processing
521    
522      #print "dir: ", $self->{args}->{direction}, "\n";
523    
524    # manipulate metainfo according to direction of synchronization    # manipulate metainfo according to direction of synchronization
525    if (lc $self->{args}->{direction} eq 'push') {    if (lc $self->{options}->{process}->{mode} eq 'push') {
526      # just do it ...      # just do it ...    (don't modify any metadata)
527    } elsif (lc $self->{args}->{direction} eq 'pull') {    
528      #print "=======SWAP", "\n";    } elsif (lc $self->{options}->{process}->{mode} eq 'pull') {
529      # swap      # swap source and target metadata
530        # TODO: introduce different mechanism to make more then two partners (descents) possible
531      ($self->{meta}->{source}, $self->{meta}->{target}) =      ($self->{meta}->{source}, $self->{meta}->{target}) =
532          ($self->{meta}->{target}, $self->{meta}->{source});          ($self->{meta}->{target}, $self->{meta}->{source});
533    } elsif (lc $self->{args}->{direction} eq 'full') {      #($self->{options}->{source}, $self->{options}->{target}) =
534        #    ($self->{options}->{target}, $self->{options}->{source});
535      
536      } elsif (lc $self->{options}->{process}->{mode} eq 'full') {
537        # TODO:
538        # do a pull first and a push afterwards
539        # this requires us to be called somehow recursively - just one recursion level  ;-)
540      
541    } else {    } else {
542        # TODO: are there any other synchronization modes besides PULL, PUSH, FULL?
543      
544    }    }
545    
546    # import flag means: prepare the source node to be syncable    # import flag means: prepare the source node to be syncable
547    # this is useful if there are e.g. no "ident" or "checksum" columns yet inside a DBI like (row-based) storage    # this is useful if there are e.g. no "ident" or "checksum" columns yet inside a DBI like (row-based) storage
548    if ($self->{args}->{prepare}) {    if ($self->{options}->{process}->{prepare}) {
549      $self->_prepareNode_MetaProperties('source');      $self->_prepareNode_MetaProperties('source');
550      $self->_prepareNode_DummyIdent('source');      $self->_prepareNode_DummyIdent('source');
551      #return;      #return;
# Line 458  sub _prepareSync { Line 554  sub _prepareSync {
554        
555    # erase flag means: erase the target    # erase flag means: erase the target
556    #if ($opts->{erase}) {    #if ($opts->{erase}) {
557    if ($self->{args}->{erase}) {    if ($self->{options}->{process}->{erase}) {
558      # TODO: move this method to the scope of the synchronization core and wrap it around different handlers      # TODO: move this method to the scope of the synchronization core and wrap it around different handlers
559      #print "ERASE", "\n";      #print "ERASE", "\n";
560      $self->_erase_all('target');      $self->_erase_all('target');
# Line 468  sub _prepareSync { Line 564  sub _prepareSync {
564    
565  }  }
566    
567    sub _getDirectedArrow {
568      my $self = shift;
569      my $mode = shift;
570      $mode ||= '';
571      
572      if (lc $mode eq 'push') {
573        return '->';
574      } elsif (lc $mode eq 'pull') {
575        return '<-';
576      } elsif (lc $mode eq 'full') {
577        return '<->';
578      } else {
579        return '';
580      }
581    }
582    
583  1;  1;

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.8

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