File Coverage

blib/lib/WebService/MODIS.pm
Criterion Covered Total %
statement 96 409 23.4
branch 20 184 10.8
condition 0 12 0.0
subroutine 15 42 35.7
pod 17 23 73.9
total 148 670 22.0


line stmt bran cond sub pod time code
1             package WebService::MODIS;
2              
3 1     1   102545 use strict;
  1         3  
  1         57  
4 1     1   6 use warnings;
  1         2  
  1         38  
5 1     1   7 use Carp;
  1         9  
  1         93  
6 1     1   7 use LWP::UserAgent;
  1         2  
  1         34  
7 1     1   6 use File::Basename;
  1         1  
  1         110  
8 1     1   1805 use File::HomeDir;
  1         7059  
  1         96  
9 1     1   9 use File::Path qw(make_path);
  1         2  
  1         89  
10 1     1   711 use Date::Simple;
  1         6171  
  1         59  
11 1     1   10 use List::Util qw(any max min none);
  1         2  
  1         5429  
12              
13             require Exporter;
14             our @ISA = qw(Exporter);
15              
16             our %EXPORT_TAGS = ( 'all' => [ qw(initCache readCache writeCache getCacheState getVersions getModisProducts getModisDates getModisGlobal) ] );
17             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
18             our @EXPORT = qw(initCache readCache writeCache getCacheState getVersions isGlobal);
19              
20             our $VERSION = '1.5';
21              
22             my %modisProducts = ();
23             my %modisDates = ();
24             my %modisGlobal = ();
25             my $modisProductsFile = "ModisProducts.pl";
26             my $modisDatesFile = "ModisDates.pl";
27             my $modisGlobalFile = "ModisGlobal.pl";
28             my $cacheDir;
29              
30             my $cacheState = '';
31              
32             my $BASE_URL = "http://e4ftl01.cr.usgs.gov";
33             my @DATA_DIR = ("MOLA", "MOLT", "MOTA");
34              
35             if (lc($^O) =~ /mswin/) {
36             $cacheDir = File::HomeDir->my_home()."/AppData/Local/WebService-MODIS";
37             } else {
38             $cacheDir = File::HomeDir->my_home()."/.cache/WebService-MODIS";
39             }
40              
41             sub new {
42 0     0 1 0 my $class = shift;
43 0         0 my %options = @_;
44 0         0 my $self = {
45             product => '',
46             version => '',
47             dates => [],
48             h => [],
49             v => [],
50             ifExactDates => 0,
51             ifExactHV => 0,
52             targetDir => ".",
53             forceReload => 0,
54             %options,
55             url => [],
56             };
57 0         0 bless($self, $class);
58              
59             # User input error checks
60 0 0       0 $self->product($self->{product}) if ($self->{product} ne '');
61 0 0       0 $self->version($self->{version}) if ($self->{version} ne '');
62 0 0       0 $self->dates($self->{dates}) if (@{$self->{dates}} != 0);
  0         0  
63 0 0       0 $self->h($self->{h}) if (@{$self->{h}} != 0);
  0         0  
64 0 0       0 $self->v($self->{v}) if (@{$self->{v}} != 0);
  0         0  
65 0 0       0 $self->ifExactDates($self->{ifExactDates}) if ($self->{ifExactDates} != 0);
66 0 0       0 $self->ifExactHV($self->{ifExactHV}) if ($self->{ifExactHV} != 0);
67              
68 0         0 return($self);
69             }
70              
71             #######################################################################
72             ### For debuging and informations
73              
74             # returns the cached products data hash
75             sub getModisProducts() {
76 0     0 0 0 return(%modisProducts);
77             }
78              
79             #returns the reference to the dates array
80             sub getModisDates($) {
81 0     0 0 0 my $product = shift;
82 0         0 return($modisDates{$product});
83             }
84              
85             # returns the cached global grid check hash
86             sub getModisGlobal() {
87 0     0 0 0 return(%modisGlobal);
88             }
89              
90             ########################################################################
91             ### Cache not related to object. Need to create own object, which gets
92             ### part of WebService::MODIS
93              
94             ### retrieve the directory structure from the server
95             sub initCache {
96             # my $self = shift;
97 1     1 1 243529 %modisProducts = getAvailProducts();
98 1         9 %modisDates = getAvailDates(\%modisProducts);
99 1         19 for (keys %modisProducts) {
100 99         483 my $check = isGlobal($_);
101 99         478 $modisGlobal{$_} = $check;
102             }
103 1         33 $cacheState = "mem";
104             }
105              
106             ### load the previously saved server side directory structure from
107             ### local files
108             sub readCache {
109             # my $self = shift;
110 0     0 1 0 my $arg = shift;
111 0 0       0 $cacheDir = $arg if ($arg);
112 0 0       0 croak "Cache directory '$cacheDir' does not exist. Use 'writeCache' create it first or check your parameter!" if (!-d $cacheDir);
113              
114 0 0       0 if (-s "$cacheDir/$modisProductsFile") {
115 0         0 %modisProducts = do "$cacheDir/$modisProductsFile";
116 0 0       0 if (-s "$cacheDir/$modisDatesFile") {
117 0         0 %modisDates = do "$cacheDir/$modisDatesFile";
118 0 0       0 if (-s "$cacheDir/$modisGlobalFile") {
119 0         0 %modisGlobal = do "$cacheDir/$modisGlobalFile";
120 0         0 $cacheState = "file";
121 0         0 return;
122             } else {
123 0         0 croak "Cache file '$cacheDir/$modisGlobalFile' is empty. Use 'writeCache' to recreate it.";
124             }
125             } else {
126 0         0 croak "Cache file '$cacheDir/$modisDatesFile' is empty. Use 'writeCache' to recreate it.";
127             }
128             } else {
129 0         0 croak "Cache file '$cacheDir/$modisProductsFile' is empty. Use 'writeCache' to recreate it.";
130             }
131 0         0 return(99);
132             }
133              
134             ### write the server side directory structure to local files
135             sub writeCache {
136             # my $self = shift;
137 0     0 1 0 my $arg = shift;
138 0 0       0 $cacheDir = $arg if ($arg);
139              
140 0 0       0 croak "Nothing cached yet!" if ($cacheState eq '');
141 0 0       0 carp "Rewriting old cache to file" if ($cacheState eq 'file');
142              
143 0 0       0 if ( ! -d $cacheDir ) {
144 0 0       0 make_path($cacheDir) or croak "Could not create cache dir ('$cacheDir'): $!";
145             }
146              
147 0         0 my $fhd;
148              
149 0 0       0 open($fhd, ">", "$cacheDir/$modisProductsFile") or
150             croak "cannot open '$cacheDir/$modisProductsFile' for writing: $!\n";
151 0         0 for (keys %modisProducts) {
152 0         0 print $fhd "'$_' => '$modisProducts{$_}',\n";
153             }
154 0 0       0 close($fhd) or carp "close '$cacheDir/$modisProductsFile' failed: $!";
155              
156 0 0       0 open($fhd, ">", "$cacheDir/$modisDatesFile") or
157             croak "cannot open '$cacheDir/$modisDatesFile' for writing: $!\n";
158 0         0 for (keys %modisDates) {
159 0         0 print $fhd "'$_' => ['".join("', '", @{$modisDates{$_}})."'],\n";
  0         0  
160             }
161 0 0       0 close($fhd) or carp "close '$cacheDir/$modisDatesFile' failed: $!";
162              
163 0 0       0 open($fhd, ">", "$cacheDir/$modisGlobalFile") or
164             croak "cannot open '$cacheDir/$modisGlobalFile' for writing: $!\n";
165 0         0 for (keys %modisGlobal) {
166 0         0 print $fhd "'$_' => $modisGlobal{$_},\n";
167             }
168              
169 0         0 $cacheState = "file";
170             }
171              
172             sub getCacheState {
173             # my $self = shift;
174 0     0 1 0 return $cacheState;
175             }
176              
177             ### return a list of available version for a given product
178             sub getVersions($) {
179 0     0 1 0 my $product = shift;
180 0         0 my @versions = ();
181 0         0 foreach (keys %modisProducts) {
182 0 0       0 next if (! /$product/);
183 0         0 s/$product.//;
184 0         0 push(@versions, $_);
185             }
186 0         0 return(@versions);
187             }
188              
189             ### check is Product is global or on sinusoidal grid (with h??v?? in name)
190             sub isGlobal($) {
191 99     99 1 244 my $product = shift;
192 99         214 my $global = 1;
193              
194 99 50   4950   3959 croak "'$product' is not in the MODIS product list: Check name or refresh the cache." if (! any { /$product/ } keys %modisProducts);
  4950         9163  
195              
196 99         960 my @flist = getDateFullURLs($product, ${$modisDates{$product}}[0]);
  99         635  
197 99         972 my $teststr = $flist[0];
198 99         900 $teststr =~ s/.*\///;
199 99 100       624 $global = 0 if ($teststr =~ /h[0-9]{2}v[0-9]{2}/);
200 99         1848 return($global);
201             }
202              
203             ##################################################
204             ### methods for returning object informations
205             ### or setting them
206              
207             sub product {
208 0     0 1 0 my $self = shift;
209              
210 0 0       0 if (@_) {
211 0 0       0 if ($cacheState eq '') {
212 0         0 carp "Cache not initialized or loaded, cannot check availability of '$_[0]'.";
213             } else {
214 0         0 my $failed=1;
215 0 0   0   0 $failed = 0 if any { /$_[0]\.[0-9]{3}/ } (keys %modisProducts);
  0         0  
216 0 0       0 croak "Product '$_[0]' not available!" if $failed;
217             }
218 0         0 $self->{product} = shift;
219 0         0 $self->{version} = '';
220 0         0 $self->{url} =[];
221 0         0 return;
222             }
223 0         0 return $self->{product};
224             }
225              
226             sub version {
227 0     0 1 0 my $self = shift;
228 0 0       0 if (@_) {
229 0         0 $self->{version} = shift;
230 0 0       0 if ($self->{product} eq '') {
231 0         0 carp "No product specified yet, so specifying the version does not make sense.";
232             } else {
233 0         0 my @vers = getVersions($self->{product});
234 0 0   0   0 if (none {/$self->{version}/} @vers) {
  0         0  
235 0         0 carp "Version ".$self->{version}." does not exist! Resetting it to ''.";
236 0         0 $self->{version} = ''
237             }
238             }
239 0         0 $self->{url} = [];
240 0         0 return;
241             }
242 0         0 return $self->{version};
243             }
244              
245             sub dates {
246 0     0 1 0 my $self = shift;
247 0 0       0 if (@_) {
248 0         0 my $refDates = shift;
249 0 0       0 if ($self->{product} eq '') {
250 0         0 carp "No product specified yet, No availability check possible.";
251             } else {
252             # check availability
253             }
254 0         0 $self->{dates} = $refDates;
255 0         0 $self->{url} = [];
256 0         0 return;
257             }
258 0         0 return @{$self->{dates}};
  0         0  
259             }
260              
261             sub h {
262 0     0 1 0 my $self = shift;
263 0 0       0 if (@_) {
264 0         0 my $refH = shift;
265 0 0   0   0 if (any {$_ < 0 or $_ > 35} @$refH) {
  0 0       0  
266 0         0 croak "Invalid h values supplied. Valid range: 0-35.";
267             }
268 0         0 $self->{h} = $refH;
269 0         0 $self->{url} = [];
270 0         0 return;
271             }
272 0         0 return @{$self->{h}};
  0         0  
273             }
274              
275             sub v {
276 0     0 1 0 my $self = shift;
277 0 0       0 if (@_) {
278 0         0 my $refV = shift;
279 0 0   0   0 if (any {$_ < 0 or $_ > 17} @$refV) {
  0 0       0  
280 0         0 croak "Invalid v values supplied. Valid range: 0-17.";
281             }
282 0         0 $self->{v} = $refV;
283 0         0 $self->{url} = [];
284 0         0 return;
285             }
286 0         0 return @{$self->{v}};
  0         0  
287             }
288              
289             sub ifExactDates {
290 0     0 1 0 my $self = shift;
291 0 0       0 if (@_) {
292 0         0 my $nDates = @{$self->{dates}};
  0         0  
293 0 0       0 carp "Sure you want to set this before setting the dates!" if ($nDates==0);
294 0         0 $self->{ifExactDates} = shift;
295 0         0 $self->{url} = [];
296 0         0 return;
297             }
298 0         0 return $self->{ifExactDates};
299             }
300              
301             sub ifExactHV {
302 0     0 1 0 my $self = shift;
303 0 0       0 if (@_) {
304             # include error checks
305 0         0 my $nH = @{$self->{h}};
  0         0  
306 0         0 my $nV = @{$self->{v}};
  0         0  
307 0 0 0     0 carp "You are setting 'ifExactHV' before setting 'h' and/or 'v'!" if ($nH==0 or $nV==0);
308 0         0 $self->{ifExactHV} = shift;
309 0         0 $self->{url} = [];
310 0         0 return;
311             }
312 0 0       0 if ($self->{ifExactHV}) {
313 0         0 my $nH = @{$self->{h}};
  0         0  
314 0         0 my $nV = @{$self->{v}};
  0         0  
315 0 0 0     0 carp "You set 'ifExactHV' before setting 'h' and/or 'v'!" if ($nH==0 or $nV==0);
316 0 0       0 carp "If ifExactHV is set, 'h' and 'v' should have equal length!" if ($nH != $nV);
317             }
318 0         0 return $self->{ifExactHV};
319             }
320              
321             sub url {
322 0     0 1 0 my $self = shift;
323 0         0 return @{$self->{url}};
  0         0  
324             }
325              
326             ########################################################################
327             ### method initializing the URL list
328             ### does not need to be done by hand, is called from within download method.
329             ### This method also checks for all invalid combinations.
330              
331             sub createUrl {
332 0     0 1 0 my $self = shift;
333 0         0 my $product = $self->{product};
334              
335 0 0   0   0 croak "Product '$product' unknown!" if (! any { /$product/ } (keys %modisProducts));
  0         0  
336              
337 0         0 my $version = $self->{version};
338 0         0 my @availVersions = getVersions($product);
339              
340             ### check the MODIS product version
341 0 0       0 if ($version ne '') {
342 0 0   0   0 if (any { /$version/ } @availVersions) {
  0         0  
343 0         0 $product = "${product}.${version}";
344             } else {
345 0         0 croak "Version $version not available for $product (available: ".join(" ,", @availVersions).").\n";
346             }
347             } else {
348 0         0 $version='000';
349 0         0 foreach (@availVersions) {
350 0 0       0 $version = $_ if (int($_) > int($version));
351             }
352 0         0 $product = "${product}.${version}";
353             }
354 0         0 $self->{version} = $version;
355              
356             ### check the product date availability and reset the $self->{dates} array
357 0 0       0 if ($self->{ifExactDates}) {
358 0         0 my @dates = @{$self->{dates}};
  0         0  
359 0         0 my @cleanedDates = @dates;
360 0         0 foreach (@dates) {
361 0         0 my $failed = 0;
362 0 0   0   0 $failed=1 if none { /$_/ } @{$modisDates{$product}};
  0         0  
  0         0  
363 0 0       0 if ($failed) {
364 0         0 @cleanedDates = grep { $_ != $_ } @cleanedDates;
  0         0  
365 0         0 carp "Date '$_' not available! Removing it from list";
366             }
367             }
368 0         0 @dates = ();
369 0         0 foreach (@cleanedDates) {
370 0         0 s/\./\-/g;
371 0         0 push(@dates, Date::Simple->new($_));
372             }
373 0         0 $self->{dates} = \@dates;
374             } else {
375 0         0 my @dates = @{$self->{dates}};
  0         0  
376 0         0 my @newDates = ();
377 0         0 foreach (@dates) {
378 0         0 s/\./\-/g;
379 0         0 push(@newDates, Date::Simple->new($_));
380             }
381 0         0 my @cleanedDates = ();
382 0         0 foreach (@{$modisDates{$product}}) {
  0         0  
383 0         0 s/\./\-/g;
384 0         0 my $modisDate = Date::Simple->new($_);
385 0 0       0 next if ($modisDate - min(@newDates) < 0);
386 0 0       0 next if ($modisDate - max(@newDates) > 0);
387 0         0 push(@cleanedDates, $modisDate);
388             }
389 0         0 $self->{dates} = \@cleanedDates;
390             }
391              
392             ### check the h and v availability, but only if necessary
393 0 0       0 if (!$modisGlobal{$product}) {
394 0         0 my @h = @{$self->{h}};
  0         0  
395 0         0 my @v = @{$self->{v}};
  0         0  
396 0 0       0 if ($self->{ifExactHV}) {
397 0         0 my $nH = @{$self->{h}};
  0         0  
398 0         0 my $nV = @{$self->{v}};
  0         0  
399 0 0       0 if ($nH != $nV) {
400 0 0       0 carp "If ifExactHV is set, 'h' and 'v' should have equal length!" if ($nH != $nV);
401 0         0 @h = splice(@h, 0, min($nH, $nV));
402 0         0 @v = splice(@v, 0, min($nH, $nV));
403             }
404             } else {
405 0         0 my @newH = ();
406 0         0 my @newV = ();
407 0         0 foreach my $h (min(@h)..max(@h)) {
408 0         0 foreach my $v (min(@v)..max(@v)) {
409 0         0 push(@newH, $h);
410 0         0 push(@newV, $v);
411             }
412             }
413 0         0 $self->{h} = \@newH;
414 0         0 $self->{v} = \@newV;
415             }
416             }
417              
418 0         0 my @url = ();
419 0         0 foreach (@{$self->{dates}}) {
  0         0  
420 0         0 my @fullUrl = getDateFullURLs($product, $_->format("%Y.%m.%d"));
421 0 0       0 if (!$modisGlobal{$product}) {
422 0         0 my $nHV = @{$self->{h}};
  0         0  
423 0         0 for (my $i=0; $i < $nHV; $i++) {
424 0         0 my $pat = sprintf("h%02iv%02i", ${$self->{h}}[$i], ${$self->{v}}[$i]);
  0         0  
  0         0  
425 0         0 my @newUrl;
426 0         0 foreach (@fullUrl) {
427 0 0       0 if (/$pat/) {
428 0         0 push(@newUrl, $_);
429             }
430             }
431 0         0 my $nNewUrl = @newUrl;
432 0 0       0 if ($nNewUrl == 1) {
    0          
433 0         0 push(@url, $newUrl[0]);
434             } elsif ($nNewUrl < 1) {
435 0         0 carp(sprintf("$product: Missing file for %s @ %s.\n", $pat, $_->format("%Y.%m.%d")));
436             } else {
437             # check for duplicate files here and choose the latest one
438 0         0 carp(sprintf("$product: %i files for %s @ %s, choosing the newest.\n", $nNewUrl, $pat, $_->format("%Y.%m.%d")));
439 0         0 my $createDate = $newUrl[0];
440 0         0 $createDate =~ s/\.hdf$//;
441 0         0 $createDate =~ s/^.*\.//g;
442 0         0 $createDate = int($createDate);
443 0         0 my $newest = 0;
444 0         0 for (my $k=0; $k < $nNewUrl; $k++) {
445 0         0 s/\.hdf$//;
446 0         0 s/^.*\.//g;
447 0 0       0 if (int($_) > $createDate) {
448 0         0 $newest = $k;
449 0         0 $createDate = int($_);
450             }
451             }
452 0         0 push(@url, $newUrl[$newest]);
453             }
454             }
455             } else {
456 0         0 my $nUrl = @fullUrl;
457 0 0       0 if ($nUrl == 1) {
    0          
458 0         0 push(@url, $fullUrl[0]);
459             } elsif ($nUrl < 1) {
460 0         0 carp(sprintf("$product: Missing file @ %s.\n", $_->format("%Y.%m.%d")));
461             } else {
462             # check for duplicate files here and choose the latest one
463 0         0 warn(sprintf("$product: %i files @ %s, choosing the newest.\n", $nUrl, $_->format("%Y.%m.%d")));
464 0         0 my $createDate = $fullUrl[0];
465 0         0 $createDate =~ s/\.hdf$//;
466 0         0 $createDate =~ s/^.*\.//g;
467 0         0 $createDate = int($createDate);
468 0         0 my $newest = 0;
469 0         0 for (my $k=0; $k < $nUrl; $k++) {
470 0         0 s/\.hdf$//;
471 0         0 s/^.*\.//g;
472 0 0       0 if (int($_) > $createDate) {
473 0         0 $newest = $k;
474 0         0 $createDate = int($_);
475             }
476             }
477 0         0 push(@url, $fullUrl[$newest]);
478             }
479             }
480             }
481 0         0 $self->{url} = \@url;
482             }
483              
484             ########################################################################
485             ### method for download
486              
487             sub download {
488 0     0 1 0 my $self = shift;
489 0         0 my $arg = shift;
490 0 0       0 $self->{targetDir} = $arg if ($arg);
491 0         0 $arg = shift;
492 0 0       0 $self->{forceReload} = $arg if ($arg);
493              
494 0         0 my $nUrl = @{$self->{url}};
  0         0  
495              
496 0 0       0 $self->createUrl if ($nUrl == 0);
497 0         0 $nUrl = @{$self->{url}};
  0         0  
498              
499 0 0       0 if (! -d $self->{targetDir}) {
500 0         0 my $failed = 1;
501 0 0       0 make_path($self->targetDir) and $failed = 0;
502 0 0       0 if ($failed) {
503 0         0 croak "Cannot create directory '$self->{targetDir}': $!\n";
504             }
505             }
506              
507             # adjusted from http://stackoverflow.com/questions/6813726/continue-getting-a-partially-downloaded-file
508 0         0 my $ua = LWP::UserAgent->new();
509              
510 0         0 for (my $i=0; $i < $nUrl; $i++) {
511 0         0 my $file = $self->{targetDir}."/".basename(@{$self->{url}}[$i]);
  0         0  
512 0 0 0     0 unlink($file) if ($self->{forceReload} && -f $file);
513 0         0 my $failed = 1;
514 0 0       0 open(my $fh, '>>:raw', $file) and $failed = 0;
515 0 0       0 if ($failed) {
516 0         0 croak "Cannot open '$file': $!\n";
517             }
518 0         0 my $bytes = -s $file;
519 0         0 my $res;
520 0 0 0     0 if ( $bytes && ! $self->{forceReload}) {
521             #print "resume ${$self->{url}}[$i] -> $file ($bytes) " if ($verbose);
522 0         0 $res = $ua->get(
523             ${$self->{url}}[$i],
524             'Range' => "bytes=$bytes-",
525 0     0   0 ':content_cb' => sub { my ( $chunk ) = @_; print $fh $chunk; }
  0         0  
526 0         0 );
527             } else {
528             #print "$URL[$i] -> $destination[$i] " if ($verbose);
529 0         0 $res = $ua->get(
530             ${$self->{url}}[$i],
531 0     0   0 ':content_cb' => sub { my ( $chunk ) = @_; print $fh $chunk; }
  0         0  
532 0         0 );
533             }
534 0         0 close $fh;
535              
536 0         0 my $status = $res->status_line;
537 0 0       0 if ( $status =~ /^(200|206|416)/ ) {
538             #print "OK\n" if ($verbose && $status =~ /^20[06]/);
539             #print "already complete\n" if ($verbose && $status =~ /^416/);
540             } else {
541 0         0 print "DEBUG: $status what happend?";
542             }
543             }
544             }
545              
546             ###################################################
547             ###################################################
548             ### Internal functions
549              
550             ### retrieve a list of available MODIS Products
551             ### and return a hash with the name of the first subdirectory
552             sub getAvailProducts () {
553 1     1 0 69 my $caller = (caller)[0];
554 1 50       9 carp "This is an internal WebService::MODIS function. You should know what you are doing." if ($caller ne "WebService::MODIS");
555              
556 1         4 my %lookupTable = ();
557 1         13 my $ua = new LWP::UserAgent;
558 1         278 foreach my $subdir (@DATA_DIR) {
559 3         26 my $response = $ua->get("${BASE_URL}/${subdir}");
560              
561 3 50       1576993 unless ($response->is_success) {
562 0         0 die $response->status_line;
563             }
564              
565 3         47 my $content = $response->decoded_content();
566 3         908 my @content = split("\n", $content);
567 3         12 foreach (@content) {
568 162 100       351 next if (!/href="M/);
569 99         403 s/.*href="//;
570 99         212 s/\/.*//;
571              
572 99 50       201 print "Key already exists\n" if exists $lookupTable{$_};
573 99 50       148 print "Key already defined\n" if defined $lookupTable{$_};
574 99 50       147 print "True\n" if $lookupTable{$_};
575              
576 99         209 $lookupTable{$_} = $subdir;
577             }
578             }
579 1         79 return %lookupTable;
580             }
581              
582             ### get the available second level directories, named by date
583             ### (YYYY.MM.DD) under which the hdf files reside. This does
584             ### not ensure that the files are really there.
585             sub getAvailDates() {
586 1     1 0 6 my $caller = (caller)[0];
587 1 50       4 carp "This is an internal WebService::MODIS function. You should know what you are doing." if ($caller ne "WebService::MODIS");
588              
589 1         2 my %lookupTable = ();
590              
591 1         33 my $ua = new LWP::UserAgent;
592 1         195 foreach my $key (keys %modisProducts) {
593 99         384 my @dates=();
594 99         1354 my $response = $ua->get("${BASE_URL}/$modisProducts{$key}/$key");
595              
596 99 50       112299833 unless ($response->is_success) {
597 0         0 die $response->status_line;
598             }
599              
600 99         1841 my $content = $response->decoded_content();
601 99         402771 my @content = split("\n", $content);
602 99         4673 foreach (@content) {
603 151347 100       391436 next if (!/href="20[0-9]{2}\.[0-9]{2}\.[0-9]{2}/);
604 149268         438160 s/.*href="//;
605 149268         355042 s/\/.*//;
606 149268         191477 push(@dates, $_);
607             }
608 99         23918 my $datesString = "['".join("', '", @dates)."']";
609 99         174772 $lookupTable{$key} = eval $datesString;
610             }
611 1         128 return %lookupTable;
612             }
613              
614             ### return a file list for one product and date on the server
615             sub getDateFullURLs($$) {
616 99     99 0 722 my $caller = (caller)[0];
617 99 50       502 carp "This is an internal WebService::MODIS function. You should know what you are doing." if ($caller ne "WebService::MODIS");
618              
619 99         189 my $product = shift;
620 99         177 my $date = shift;
621              
622 99         216 my @flist = ();
623              
624 99         1098 my $ua = new LWP::UserAgent;
625              
626 99         27086 my $response = $ua->get("${BASE_URL}/$modisProducts{$product}/$product/$date");
627            
628 99 50       144314478 unless ($response->is_success) {
629 0         0 die $response->status_line;
630             }
631              
632 99         2206 my $content = $response->decoded_content();
633 99         274218 my @content = split("\n", $content);
634 99         2468 foreach (@content) {
635 70945 100       127839 next if (!/href="M/);
636 40302 100       97971 next if (/hdf.xml/);
637 20151         80519 s/.*href="//;
638 20151         51859 s/".*//;
639 20151         50225 push(@flist, "${BASE_URL}/$modisProducts{$product}/$product/$date/$_");
640             }
641 99         20727 return(@flist);
642             }
643              
644             1;
645              
646             __END__