/[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.1 - (show annotations)
Sun Jan 19 01:23:04 2003 UTC (21 years, 5 months ago) by joko
Branch: MAIN
+ new from Data/Transfer/Sync.pm

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

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