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

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.5

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