IODA Bundle
FileMapper.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 1996-2013 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 #include <ctype.h>
12 
13 #include "eckit/thread/AutoLock.h"
14 #include "eckit/thread/Mutex.h"
15 #include "eckit/types/Types.h"
16 #include "eckit/utils/StringTools.h"
17 #include "eckit/filesystem/PathName.h"
18 #include "eckit/config/Resource.h"
19 
20 #include "odc/FileMapper.h"
21 #include "odc/FileCollector.h"
22 
23 using namespace eckit;
24 using namespace std;
25 
26 typedef StringTools S;
27 
28 static Mutex local_mutex;
29 
30 FileMapper::FileMapper(const string& pathNameSchema)
31 {
32  parsePathNameSchema(pathNameSchema);
33 }
34 
36 
37 // Order of keywords: /tmp/p4/mars/client/dev/grib_api/src/hypercube.c
38 
40 {
41  AutoLock<Mutex> lock(local_mutex);
42  ASSERT("FileMapper: roots_ not set" && roots_.size());
43 
44  bool atLeastOneRootExists (false);
45 
46  for (size_t i (0); i < roots_.size(); ++i)
47  {
48  bool exists (PathName(roots_[i]).exists());
49 
50  Log::info() << "checkRoots: " << i << ": " << roots_[i] << " " << exists << std::endl;
51 
52  if (exists)
53  atLeastOneRootExists = true;
54  }
55  if (! atLeastOneRootExists)
56  {
57  stringstream msg;
58  msg << "No directory specified in odbServerRoots exists, checked: " << roots_[0];
59  for (size_t i(1); i < roots_.size(); ++i)
60  msg << ":" << roots_[i];
61 
62  throw UserError(msg.str());
63  }
64 }
65 
66 void FileMapper::parsePathNameSchema(const std::string& pathNameSchema)
67 {
68  AutoLock<Mutex> lock(local_mutex);
69 
70  Log::debug() << "pathNameSchema: " << pathNameSchema << std::endl;
71 
72  placeholders_.clear();
73  separators_.clear();
74  const string& s (pathNameSchema);
75  for (size_t i (0); i < s.size(); )
76  {
77  size_t begin (s.find('{', i));
78  if (begin == std::string::npos)
79  {
80  separators_.push_back(s.substr(i));
81  break;
82  }
83  size_t end (s.find('}', begin));
84  ASSERT(end != std::string::npos);
85 
86  separators_.push_back(s.substr(i, begin - i));
87  placeholders_.push_back(s.substr(begin + 1, end - begin - 1));
88 
89  i = end + 1;
90  }
91 
92  // TODO: keywords_ needs to be sorted as in //depot/mars/client/dev/grib_api/src/hypercube.c
93  //keywords_ = placeholders_;
94 
95  Log::debug() << "pathNameSchema: separators_=" << separators_ << std::endl;
96  Log::debug() << "pathNameSchema: placeholders_ =" << placeholders_ << std::endl;
97 }
98 
99 std::vector<std::string> FileMapper::keywords() const { return placeholders_; }
100 
101 void FileMapper::addRoot(const std::string& p)
102 {
103  roots_.push_back(FileCollector::expandTilde(p));
104 }
105 
106 void FileMapper::addRoots(const std::vector<std::string>& roots)
107 {
108  for (size_t i (0); i < roots.size(); ++i)
109  addRoot(roots[i]);
110 }
111 
112 string FileMapper::patchTime(const string& s) const
113 {
114  ASSERT("Format of time" && s.size() != 3 && !(s.size() > 6));
115  string r (s);
116 
117  // This option exists to replace the compile time option ODB_SERVER_TIME_FORMAT_FOUR_DIGITS
118  // This exists to support differences in usage between the Met Office and ECMWF
119 
120  bool odbServerTimeFormat4Digits = eckit::Resource<bool>("odbServerTimeFormat,$ODB_SERVER_TIME_FORMAT_FOUR_DIGITS", false);
121 
122  if(odbServerTimeFormat4Digits) {
123  if (s.size() == 1) r = string("0") + s + "00";
124  // '60000' => '0600'
125  if (s.size() == 5) r = string("0") + s.substr(0,3);
126  // '120000' => '1200'
127  if (s.size() == 6) r = s.substr(0,4);
128 
129  ASSERT(r.size() == 4); // We want time as four digits, don't we....
130  }
131  else {
132  if (s.size() == 1) r = string("0") + s;
133  // HACK: for TIME '0600' => '06'
134  if (s.size() == 4) r = s.substr(0,2);
135  // '60000' => '06'
136  if (s.size() == 5) r = string("0") + s.substr(0,1);
137  // '120000' => '12'
138  if (s.size() == 6) r = s.substr(0,2);
139 
140  ASSERT(r.size() == 2); // We want time as two digits, don't we....
141  }
142 
143  return r;
144 }
145 
146 string FileMapper::encodeRelative(const std::map<std::string,std::string>& values) const
147 {
148  ostream& L(Log::info());
149  L << "FileMapper::encode: values:" << endl;
150  for (map<string,string>::const_iterator it(values.begin()); it != values.end(); ++it)
151  L << " " << it->first << ":" << it->second << endl;
152 
153  stringstream r;
154  size_t pi (0);
155  for (size_t i (0); i < separators_.size(); ++i)
156  {
157  r << separators_[i];
158  if (pi < placeholders_.size())
159  {
160  string placeholder (S::upper(placeholders_[pi++]));
161 
162  const map<string,string>::const_iterator end(values.end());
163 
164  if (values.find(placeholder) == end && values.find(S::lower(placeholder)) == end)
165  throw UserError(string("Could not find value of '") + placeholder + "' in values suplied.");
166 
167  const map<string,string>::const_iterator it( values.find(placeholder) != end
168  ? values.find(placeholder)
169  : values.find(S::lower(placeholder)) );
170 
171  string value (it->second);
172 
173  /// @note behaviour here has been changed. Old behaviour ran patchTime on both TIME and ANTIME, this
174  /// does not match correct usage in (ECMWF) operations, and this now ONL patches ANTIME, unles
175  /// overridden with a Resource
176 
177  bool patchTimeEncodeRelative = eckit::Resource<bool>("odbPatchTimeEncodeRelative;$ODB_PATCH_TIME_ENCODE_RELATIVE", false);
178 
179  string patchedValue = value;
180  if (S::upper(placeholder) == "ANTIME" || (patchTimeEncodeRelative && S::upper(placeholder) == "TIME")) {
181  patchedValue = patchTime(value);
182  }
183 
184  if (value != patchedValue)
185  L << "FileMapper::encodeRelative: value of '" << placeholder << "' was '" << value << "' changed to '" << patchedValue << "'" << endl;
186 
187  r << patchedValue;
188  }
189  }
190  return r.str();
191 }
192 
193 vector<string> FileMapper::encode(const std::map<std::string,std::string>& values) const
194 {
195  string path (encodeRelative(values));
196  vector<string> r;
197  for (size_t i (0); i < roots_.size(); ++i)
198  r.push_back(roots_[i] + '/' + path);
199  return r;
200 }
StringTools S
Definition: FileMapper.cc:26
static Mutex local_mutex
Definition: FileMapper.cc:28
static std::string expandTilde(const std::string &s)
std::vector< std::string > encode(const std::map< std::string, std::string > &values) const
Definition: FileMapper.cc:193
std::string encodeRelative(const std::map< std::string, std::string > &values) const
Definition: FileMapper.cc:146
void addRoot(const std::string &)
Definition: FileMapper.cc:101
void checkRoots() const
Definition: FileMapper.cc:39
FileMapper(const std::string &pathNameSchema)
Definition: FileMapper.cc:30
std::vector< std::string > keywords() const
Definition: FileMapper.cc:99
std::string patchTime(const std::string &) const
Definition: FileMapper.cc:112
void parsePathNameSchema(const std::string &pathNameSchema)
Definition: FileMapper.cc:66
void addRoots(const std::vector< std::string > &)
Definition: FileMapper.cc:106
real(kind_real), parameter, public pi
Pi.
Definition: encode.cc:30