OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
ScanElement.cc
Go to the documentation of this file.
1 // This file is part of the "NcML Module" project, a BES module designed
3 // to allow NcML files to be used to be used as a wrapper to add
4 // AIS to existing datasets of any format.
5 //
6 // Copyright (c) 2009 OPeNDAP, Inc.
7 // Author: Michael Johnson <m.johnson@opendap.org>
8 //
9 // For more information, please also see the main website: http://opendap.org/
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // Please see the files COPYING and COPYRIGHT for more information on the GLPL.
26 //
27 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
29 #include "config.h"
30 
31 #include "ScanElement.h"
32 
33 #include <algorithm> // std::sort
34 #include <cstring>
35 #include <cerrno>
36 #include <dirent.h>
37 #include <iostream>
38 #include <sstream>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 
43 #include "AggregationElement.h"
44 #include "DirectoryUtil.h" // agg_util
45 #include "NCMLDebug.h"
46 #include "NCMLParser.h"
47 #include "NetcdfElement.h"
48 #include "RCObject.h"
49 #include "SimpleTimeParser.h"
50 #include "XMLHelpers.h"
51 
52 #include "Error.h" // libdap
53 
54 // ICU includes for the SimpleDateFormat used in this file only
55 #include <unicode/smpdtfmt.h> // class SimpleDateFormat
56 #include <unicode/timezone.h> // class TimeZone
57 
58 using agg_util::FileInfo;
60 
61 namespace ncml_module
62 {
63  const string ScanElement::_sTypeName = "scan";
64  const vector<string> ScanElement::_sValidAttrs = getValidAttributes();
65 
66  // The rep for the opaque pointer in the header.
67  struct ScanElement::DateFormatters
68  {
69  DateFormatters() : _pDateFormat(0), _pISO8601(0), _markPos(0), _sdfLen(0) {}
70  ~DateFormatters()
71  {
72  SAFE_DELETE(_pDateFormat);
73  SAFE_DELETE(_pISO8601);
74  }
75 
76  // If we have a _dateFormatMark, we'll create a single
77  // instance of the icu SimpleDateFormat in order
78  // to process each file.
79  SimpleDateFormat* _pDateFormat;
80  // We also will create a single instance of a format
81  // for ISO 8601 times for output into the coordinate
82  SimpleDateFormat* _pISO8601;
83 
84  // The position of the # mark in the date format string
85  // We match the preceding characters with the filename.
86  size_t _markPos;
87 
88  // The length of the pattern we actually use for the
89  // simple date format. Thus the SDF pattern is
90  // the portion of the string from _markPos+1 to _sdfLen.
91  size_t _sdfLen;
92  };
93 
95  : RCObjectInterface()
96  , NCMLElement(0)
97  , _location("")
98  , _suffix("")
99  , _regExp("")
100  , _subdirs("")
101  , _olderThan("")
102  , _dateFormatMark("")
103  , _enhance("")
104  , _ncoords("")
105  , _pParent(0)
106  , _pDateFormatters(0)
107  {
108  }
109 
111  : RCObjectInterface()
112  , NCMLElement(0)
113  , _location(proto._location)
114  , _suffix(proto._suffix)
115  , _regExp(proto._regExp)
116  , _subdirs(proto._subdirs)
117  , _olderThan(proto._olderThan)
118  , _dateFormatMark(proto._dateFormatMark)
119  , _enhance(proto._enhance)
120  , _ncoords(proto._ncoords)
121  , _pParent(proto._pParent) // weak ref so this is fair...
122  , _pDateFormatters(0)
123  {
124  if (!_dateFormatMark.empty())
125  {
126  initSimpleDateFormats(_dateFormatMark);
127  }
128  }
129 
131  {
132  deleteDateFormats();
133  _pParent = 0;
134  }
135 
138  {
139  return _pParent;
140  }
141 
142  void
144  {
145  _pParent = pParent;
146  }
147 
148  const string&
150  {
151  return _sTypeName;
152  }
153 
154  ScanElement*
156  {
157  return new ScanElement(*this);
158  }
159 
160  void
162  {
163  _location = attrs.getValueForLocalNameOrDefault("location", "");
164  _suffix = attrs.getValueForLocalNameOrDefault("suffix", "");
165  _regExp = attrs.getValueForLocalNameOrDefault("regExp", "");
166  _subdirs = attrs.getValueForLocalNameOrDefault("subdirs", "true");
167  _olderThan = attrs.getValueForLocalNameOrDefault("olderThan", "");
168  _dateFormatMark = attrs.getValueForLocalNameOrDefault("dateFormatMark", "");
169  _enhance = attrs.getValueForLocalNameOrDefault("enhance", "");
170  _ncoords = attrs.getValueForLocalNameOrDefault("ncoords", "");
171 
172  // default is to print errors and throw which we want.
174 
175  // Until we implement them, we'll throw parse errors for those not yet implemented.
176  throwOnUnhandledAttributes();
177 
178  // Create the SimpleDateFormat's if we have a _dateFormatMark
179  if (!_dateFormatMark.empty())
180  {
181  initSimpleDateFormats(_dateFormatMark);
182  }
183  }
184 
185  void
187  {
188  if (!_parser->isScopeAggregation())
189  {
191  "ScanElement: " + toString() + " "
192  "was not the direct child of an <aggregation> element as required!");
193  }
194  }
195 
196  void ScanElement::handleContent(const string& content)
197  {
198  // shouldn't be any, use the super impl to throw if not whitespace.
200  }
201 
203  {
204  // Get to the our parent aggregation so we can add
205  NetcdfElement* pCurrentDataset = _parser->getCurrentDataset();
206  VALID_PTR(pCurrentDataset);
207  AggregationElement* pParentAgg = pCurrentDataset->getChildAggregation();
208  NCML_ASSERT_MSG(pParentAgg, "ScanElement::handleEnd(): Couldn't"
209  " find the the child aggregation of the current dataset, which is "
210  "supposed to be our parent!");
211  pParentAgg->addScanElement(this);
212  }
213 
214  string
216  {
217  return "<" + _sTypeName + " " +
218  "location=\"" + _location + "\" " + // always print this one even in empty.
219  printAttributeIfNotEmpty("suffix", _suffix) +
220  printAttributeIfNotEmpty("regExp", _regExp) +
221  printAttributeIfNotEmpty("subdirs", _subdirs) +
222  printAttributeIfNotEmpty("olderThan", _olderThan) +
223  printAttributeIfNotEmpty("dateFormatMark", _dateFormatMark) +
224  printAttributeIfNotEmpty("ncoords", _ncoords) +
225  ">";
226  }
227 
228  const string&
230  {
231  return _ncoords;
232  }
233 
234  bool
236  {
237  return (_subdirs == "true");
238  }
239 
240  long
242  {
243  if (_olderThan.empty())
244  {
245  return 0L;
246  }
247 
248  long secs = 0;
249  bool success = agg_util::SimpleTimeParser::parseIntoSeconds(secs, _olderThan);
250  if (!success)
251  {
253  "Couldn't parse the olderThan attribute! Expect a string of the form: "
254  "\"%d %units\" where %d is a number and %units is a time unit string such as "
255  " \"hours\" or \"s\".");
256  }
257  else
258  {
259  return secs;
260  }
261  }
262 
263  void
264  ScanElement::getDatasetList(vector<NetcdfElement*>& datasets) const
265  {
266  // Use BES root as our root
267  DirectoryUtil scanner;
268  scanner.setRootDir(scanner.getBESRootDir());
269 
270  BESDEBUG("ncml", "Scan will be relative to the BES root data path = " <<
271  scanner.getRootDir() << endl);
272 
273  setupFilters(scanner);
274 
275  vector<FileInfo> files;
276  //vector<FileInfo> dirs;
277  try // catch BES errors to give more context,,,,
278  {
279  // Call the right version depending on setting of subtree recursion.
280  if (shouldScanSubdirs())
281  {
282  scanner.getListingOfRegularFilesRecursive(_location, files);
283  }
284  else
285  {
286  scanner.getListingForPath(_location, &files, 0);
287  }
288  }
289  catch (BESNotFoundError& ex)
290  {
291  ostringstream oss;
292  oss << "In processing " << toString() << " we got a BESNotFoundError with msg=";
293  ex.dump(oss);
294  oss << " Perhaps a path is incorrect?" << endl;
295  THROW_NCML_PARSE_ERROR(line(), oss.str());
296  }
297 
298  // Let the other exceptions percolate up... Internal errors
299  // and Forbidden are pretty clear and likely not a typo
300  // in the NCML like NotFound could be.
301 
302  BESDEBUG("ncml", "Scan " << toString() << " returned matching regular files: " << endl);
303  if (files.empty())
304  {
305  BESDEBUG("ncml", "WARNING: No matching files found!" << endl);
306  }
307  else
308  {
309  DirectoryUtil::printFileInfoList(files);
310  }
311 
312  // Let the user know we're performing syntactic sugar with ncoords
313  // We'll let the other context decide whether its proper to use it.
314  if (!_ncoords.empty())
315  {
316  BESDEBUG("ncml",
317  "Scan has ncoords attribute specified: ncoords="
318  << _ncoords
319  << " Will be inherited by all matching datasets!"
320  << endl);
321  }
322 
323  // Adapt the file list into a temp vector of NetcdfElements
324  // created from the parser's factory so they
325  // get added to its memory pool
326  // We use a temp vector since we need to sort the datasets
327  // before appending them to the output dataset vector.
328  XMLAttributeMap attrs;
329  vector<NetcdfElement*> scannedDatasets;
330  scannedDatasets.reserve(files.size());
331  // Now add them...
332  for (vector<FileInfo>::const_iterator it = files.begin();
333  it != files.end();
334  ++it)
335  {
336  // start fresh
337  attrs.clear();
338 
339  // The path to the file, relative to the BES root as needed.
340  attrs.addAttribute(XMLAttribute("location", it->getFullPath()));
341 
342  // If the user has specified the ncoords sugar,
343  // pass it down into the netcdf element.
344  if (!_ncoords.empty())
345  {
346  attrs.addAttribute(XMLAttribute("ncoords", _ncoords));
347  }
348 
349  // If there's a dateFormatMark, pull out the coordVal
350  // and add it to the attrs map since we want to use that and
351  // not the location for the new map vector.
352  if (!_dateFormatMark.empty())
353  {
354  string timeCoord = extractTimeFromFilename(it->basename());
355  BESDEBUG("ncml", "Got an ISO 8601 time from dateFormatMark: " <<
356  timeCoord << endl);
357  attrs.addAttribute(XMLAttribute("coordValue", timeCoord));
358  }
359 
360  // Make the dataset using the parser so it's in the parser memory pool.
361  RCPtr<NCMLElement> dataset = _parser->_elementFactory.makeElement("netcdf", attrs, *_parser);
362  VALID_PTR(dataset.get());
363 
364  // Up the ref count (since it's in an RCPtr) and add to the result vector
365  scannedDatasets.push_back(static_cast<NetcdfElement*>(dataset.refAndGet()));
366  }
367 
368  // We have the scanned datasets in scannedDatasets vector now, so sort
369  // on location() or coordValue() depending on whether we have a dateFormatMark...
370  if (_dateFormatMark.empty()) // sort by location()
371  {
372  BESDEBUG("ncml", "Sorting scanned datasets by location()..." << endl);
373  std::sort(scannedDatasets.begin(),
374  scannedDatasets.end(),
376  }
377  else // sort by coordValue()
378  {
379  BESDEBUG("ncml", "Sorting scanned datasets by coordValue() since we got a dateFormatMark"
380  " and the coordValue are ISO 8601 dates..." << endl);
381  std::sort(scannedDatasets.begin(),
382  scannedDatasets.end(),
384  }
385 
386  // Also, if there's a dateFormatMark, we want to specify that a new
387  // _CoordinateAxisType attribute be added with value "Time" (according to NcML Aggregations page)
388  if (!_dateFormatMark.empty())
389  {
390  VALID_PTR(getParent());
392  }
393 
394  // Now we can append the sorted local vector of datasets to the output.
395  // We need not worry about reference counts since the scannedDatasets
396  // has them red'd already and won't deref when it goes out of scope.
397  // We are merely transferring them to the ouput, so the
398  // refcount is still correct as is.
399  BESDEBUG("ncml", "Adding the sorted scanned datasets to the current aggregation list..." << endl);
400  datasets.reserve(datasets.size() + scannedDatasets.size());
401  datasets.insert(datasets.end(), scannedDatasets.begin(), scannedDatasets.end());
402  }
403 
404  void
405  ScanElement::setupFilters(agg_util::DirectoryUtil& scanner) const
406  {
407  // If we have a suffix, set the filter.
408  if (!_suffix.empty())
409  {
410  BESDEBUG("ncml", "Scan will filter against suffix=\"" << _suffix << "\"" << endl);
411  scanner.setFilterSuffix(_suffix);
412  }
413 
414  if (!_regExp.empty())
415  {
416  BESDEBUG("ncml", "Scan will filter against the regExp=\"" << _regExp << "\"" << endl);
417 
418  // If there's a problem compiling it, we'll know now.
419  // So catch it and wrap it as a parse error, which tecnically it is.
420  try
421  {
422  scanner.setFilterRegExp(_regExp);
423  }
424  catch (libdap::Error& err)
425  {
427  "There was a problem compiling the regExp=\"" + _regExp +
428  "\" : "
429  + err.get_error_message());
430  }
431  }
432 
433  if (!_olderThan.empty())
434  {
435  long secs = getOlderThanAsSeconds();
436  struct timeval tvNow;
437  gettimeofday(&tvNow, 0);
438  long cutoffTime = tvNow.tv_sec - secs;
439  scanner.setFilterModTimeOlderThan(static_cast<time_t>(cutoffTime));
440  BESDEBUG("ncml", "Setting scan filter modification time using duration: "
441  << secs << " from the olderThan attribute=\"" << _olderThan << "\""
442  " The cutoff modification time based on now is: " <<
443  getTimeAsString(cutoffTime) << endl);
444  }
445  }
446 
447  // SimpleDateFormat to produce ISO 8601
448  static const string ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
449 
454  static bool convertUnicodeStringToStdString(std::string& toString, const UnicodeString& fromUniString)
455  {
456  // This call exists in 4.2 but not 4.0 or 3.6
457  // TODO use this call if we up our minimum ICU version
458  // fromUniString.toUTF8String(toString);
459 
460  toString = ""; // empty it in case of error
461  vector<char> buffer; // std::string element[0] isn't guaranteed contiguous like vectors, so we need a temp...
462  buffer.resize(fromUniString.length() + 1); // +1 for NULL terminator
463  UErrorCode errorCode = U_ZERO_ERROR;
464  int32_t patternLen = fromUniString.extract(&buffer[0], buffer.size(), 0, errorCode);
465  if (patternLen >= static_cast<int32_t>(buffer.size()) || U_FAILURE(errorCode))
466  {
467  return false;
468  }
469  else
470  {
471  toString = std::string(&buffer[0]);
472  return true;
473  }
474  }
475 
476  void
477  ScanElement::initSimpleDateFormats(const std::string& dateFormatMark)
478  {
479  // Make sure no accidental leaks
480  deleteDateFormats();
481  _pDateFormatters = new DateFormatters;
482  VALID_PTR(_pDateFormatters);
483 
484  _pDateFormatters->_markPos = dateFormatMark.find_last_of("#");
485  if (_pDateFormatters->_markPos == string::npos)
486  {
488  "The scan@dateFormatMark attribute did not contain"
489  " a marking # character before the date format!"
490  " dateFormatMark=\"" + dateFormatMark + "\"");
491  }
492 
493  // Get just the portion that is the SDF string
494  string dateFormat = dateFormatMark.substr(_pDateFormatters->_markPos+1, string::npos);
495  BESDEBUG("ncml", "Using a date format of: " << dateFormat << endl);
496  UnicodeString usDateFormat(dateFormat.c_str());
497 
498  // Cache the length of the pattern for later substr calcs.
499  _pDateFormatters->_sdfLen = dateFormat.size();
500 
501  // Try to make the formatter from the user given string
502  UErrorCode success = U_ZERO_ERROR;
503  _pDateFormatters->_pDateFormat = new SimpleDateFormat(usDateFormat, success);
504  if (U_FAILURE(success))
505  {
507  "Scan element failed to parse the SimpleDateFormat pattern: "
508  + dateFormat);
509  }
510  VALID_PTR(_pDateFormatters->_pDateFormat);
511  // Set it to the GMT timezone since we expect UTC times by default.
512  _pDateFormatters->_pDateFormat->setTimeZone(*(TimeZone::getGMT()));
513 
514  // Also create an ISO 8601 formatter for creating the coordValue's
515  // from the parsed UDate's.
516  _pDateFormatters->_pISO8601 = new SimpleDateFormat(success);
517  if (U_FAILURE(success))
518  {
520  "Scan element failed to create the ISO 8601 SimpleDateFormat"
521  " using the pattern " + ISO_8601_FORMAT);
522  }
523  VALID_PTR(_pDateFormatters->_pISO8601);
524  // We want to output UTC, so GMT as well.
525  _pDateFormatters->_pISO8601->setTimeZone(*(TimeZone::getGMT()));
526  _pDateFormatters->_pISO8601->applyPattern(ISO_8601_FORMAT.c_str());
527  }
528 
529  std::string
530  ScanElement::extractTimeFromFilename(const std::string& filename) const
531  {
532  VALID_PTR(_pDateFormatters);
533  VALID_PTR(_pDateFormatters->_pDateFormat);
534  VALID_PTR(_pDateFormatters->_pISO8601);
535 
536  // Skip the first set of chars before the # mark (we don't care that
537  // they match, just the quantity).
538  string sdfPortion = filename.substr(
539  _pDateFormatters->_markPos,
540  _pDateFormatters->_sdfLen);
541 
542  UnicodeString usPattern;
543  _pDateFormatters->_pDateFormat->toPattern(usPattern);
544  string sdfPattern;
545  bool conversionSuccess = convertUnicodeStringToStdString(sdfPattern, usPattern);
546  NCML_ASSERT_MSG(conversionSuccess,
547  "ScanElement::extractTimeFromFilename: couldn't convert the UnicodeString date pattern to a std::string!");
548 
549 
550  BESDEBUG("ncml", "Scan is now matching the date portion of the filename " <<
551  sdfPortion <<
552  " to the SimpleDateFormat="
553  "\"" << sdfPattern << "\"" <<
554  endl);
555 
556  UErrorCode status = U_ZERO_ERROR;
557  UDate theDate = _pDateFormatters->_pDateFormat->parse(sdfPortion.c_str(), status);
558  if (U_FAILURE(status))
559  {
561  "SimpleDateFormat could not parse the pattern="
562  "\"" + sdfPattern + "\""
563  " on the filename portion=" +
564  "\"" + sdfPortion + "\""
565  " of the filename=" +
566  "\"" + filename + "\""
567  " Either the pattern was invalid or the filename did not match.");
568  }
569 
570  UnicodeString usISODate;
571  _pDateFormatters->_pISO8601->format(theDate, usISODate);
572  string result;
573  conversionSuccess = convertUnicodeStringToStdString(result, usISODate);
574  NCML_ASSERT_MSG(conversionSuccess,
575  "ScanElement::extractTimeFromFilename: failed to convert the UnicodeString ISO date to a std::string!");
576  // usISODate.toUTF8String(result);
577  return result;
578  }
579 
580  void
581  ScanElement::deleteDateFormats() throw()
582  {
583  SAFE_DELETE(_pDateFormatters);
584  }
585 
586  vector<string>
587  ScanElement::getValidAttributes()
588  {
589  vector<string> attrs;
590  attrs.push_back("location");
591  attrs.push_back("suffix");
592  attrs.push_back("regExp");
593  attrs.push_back("subdirs");
594  attrs.push_back("olderThan");
595  attrs.push_back("dateFormatMark");
596 
597  // it's in the schema, but we don't support it yet.
598  // Will throw later.
599  attrs.push_back("enhance");
600 
601  // OPeNDAP extension, syntactic sugar applied to all matches.
602  attrs.push_back("ncoords");
603 
604  return attrs;
605  }
606 
607  void
608  ScanElement::throwOnUnhandledAttributes()
609  {
610  if (!_enhance.empty())
611  {
612  THROW_NCML_PARSE_ERROR(line(), "ScanElement: Sorry, enhance attribute is not yet supported.");
613  }
614  }
615 
616  std::string
617  ScanElement::getTimeAsString(time_t theTime)
618  {
619  struct tm* pTM = gmtime(&theTime);
620  char buf[128];
621  // this should be "Year-Month-Day Hour:Minute:Second"
622  strftime(buf, 128, "%F %T", pTM);
623  return string(buf);
624  }
625 
626 }
error thrown if the resource requested cannot be found
Class to hold info on files as we get them.
Definition: DirectoryUtil.h:46
void getListingOfRegularFilesRecursive(const std::string &path, std::vector< FileInfo > &rRegularFiles)
Get recursive listing of all regular files in the directory subtree.
virtual bool validateAttributes(const XMLAttributeMap &attrs, const vector< string > &validAttrs, vector< string > *pInvalidAttrs=0, bool printInvalid=true, bool throwOnError=true)
Check that the given attributes are all in the valid set, otherwise fill in *pInvalidAttrs with the p...
Definition: NCMLElement.cc:191
virtual void setAttributes(const XMLAttributeMap &attrs)
Set the attributes of this from the map.
Definition: ScanElement.cc:161
void setFilterRegExp(const std::string &regexp)
Set a (GNU style) regular expression to be used to match against the full filename (relative path und...
long getOlderThanAsSeconds() const
Get the olderThan attribute in seconds.
Definition: ScanElement.cc:241
static bool isCoordValueLexicographicallyLessThan(const NetcdfElement *pLHS, const NetcdfElement *pRHS)
Compare the coordvalue fields of the two arguments and return true if lhs.coordValue() < rhs...
#define SAFE_DELETE(a)
Definition: NCMLUtil.h:64
void getDatasetList(vector< NetcdfElement * > &datasets) const
Actually perform the filesystem scan based on the specified attributes (suffix, subdirs, etc).
Definition: ScanElement.cc:264
virtual void dump(ostream &strm) const
Displays debug information about this object.
An abstract superclass for NCMLArray that handles the non-parameterized functionality and allows u...
void getListingForPath(const std::string &path, std::vector< FileInfo > *pRegularFiles, std::vector< FileInfo > *pDirectories)
Get a listing of all the regular files and directories in the given path, which is assumed relative t...
static const string _sTypeName
Definition: ScanElement.h:54
virtual void handleContent(const string &content)
Handle the characters content for the element.
Definition: ScanElement.cc:196
#define L
Definition: avltree.h:36
void addScanElement(ScanElement *pScanner)
Add a child ScanElement to the Aggregation to be used to to add to the list of child datasets...
const string getValueForLocalNameOrDefault(const string &localname, const string &defVal="") const
If there is an attribute with localname, return its value, else return default.
Definition: XMLHelpers.cc:209
const string & ncoords() const
Definition: ScanElement.cc:229
#define NCML_ASSERT_MSG(cond, msg)
Definition: NCMLDebug.h:83
Concrete class for NcML element.
Definition: NetcdfElement.h:63
Implementation of the element used to scan directories to create the set of files for an aggre...
Definition: ScanElement.h:50
T * refAndGet() const
If not null, ref() the object and then return it.
Definition: RCObject.h:352
static bool isLocationLexicographicallyLessThan(const NetcdfElement *pLHS, const NetcdfElement *pRHS)
Compare the location fields of the two arguments and return true if lhs.location() < rhs...
void setAggregationVariableCoordinateAxisType(const std::string &cat)
If a child scan contains a dateFormatMark, then we want to add a "_CoordinateAxisType" of "Time" By s...
static const vector< string > _sValidAttrs
Definition: ScanElement.h:57
AggregationElement * getParent() const
Get the aggregation of which I am a child.
Definition: ScanElement.cc:137
AggregationElement * getChildAggregation() const
Return the raw pointer (or NULL) to our contained aggregation.
static std::string printAttributeIfNotEmpty(const std::string &attrName, const std::string &attrValue)
Helper for subclasses implementing toString().
Definition: NCMLElement.cc:240
Helper classes for using dirent.h, dir.h, stat.h, etc.
Definition: DirectoryUtil.h:88
void setFilterSuffix(const std::string &suffix)
Set the filter to be used for the nexy getListingForPath() call.
#define THROW_NCML_PARSE_ERROR(parseLine, msg)
Definition: NCMLDebug.h:69
static std::string getBESRootDir()
Gets the BES root directory by checking the bes.conf settings for BES.
A reference to an RCObject which automatically ref() and deref() on creation and destruction.
Definition: RCObject.h:279
void addAttribute(const XMLAttribute &attribute)
TODO how do we tell if this exists? Does it replace? Do we care?
Definition: XMLHelpers.cc:194
virtual void handleBegin()
Handle a begin on this element.
Definition: ScanElement.cc:186
virtual ScanElement * clone() const
Make and return a copy of this.
Definition: ScanElement.cc:155
Base class for NcML element concrete classes.
Definition: NCMLElement.h:64
virtual void handleEnd()
Handle the closing of this element.
Definition: ScanElement.cc:202
int line() const
Return the current parse line number.
Definition: NCMLElement.cc:174
virtual void handleContent(const std::string &content)
Handle the characters content for the element.
Definition: NCMLElement.cc:180
RCPtr< NCMLElement > makeElement(const std::string &eltTypeName, const XMLAttributeMap &attrs, NCMLParser &parser)
Create an element of the proper type with the given AttrMap for its defined attributes.
Definition: NCMLElement.cc:126
void setFilterModTimeOlderThan(time_t newestModTime)
Set a filter on the modification time of the files to be returned in a listing.
void clear()
make empty
Definition: XMLHelpers.cc:187
void setParent(AggregationElement *pParent)
Set the parent of this element.
Definition: ScanElement.cc:143
bool shouldScanSubdirs() const
is the subdirs attribute true?
Definition: ScanElement.cc:235
#define VALID_PTR(ptr)
Definition: NCMLDebug.h:88
T * get() const
Definition: RCObject.h:334
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
const std::string & getRootDir() const
get the current root dir
static bool parseIntoSeconds(long &seconds, const std::string &duration)
Parse the string in duration and to calculate the (approximate) number of seconds it represents...
void setRootDir(const std::string &rootDir, bool allowRelativePaths=false, bool allowSymLinks=false)
Makes sure the directory exists and is readable or throws an exception exception. ...
virtual string toString() const
Return a string describing the element.
Definition: ScanElement.cc:215
virtual const string & getTypeName() const
Return the type of the element, which should be: the same as ConcreteClassName::getTypeName() ...
Definition: ScanElement.cc:149