OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
JsonConfig.cpp
Go to the documentation of this file.
1 //**************************************************************************************************
2 //
3 // OSSIM Open Source Geospatial Data Processing Library
4 // See top level LICENSE.txt file for license information
5 //
6 //**************************************************************************************************
7 
12 #include <ossim/base/ossimNotify.h>
14 #include <memory>
15 
16 using namespace std;
17 
18 namespace ossim
19 {
20 JsonParam JsonConfig::s_nullParam;
21 
22 JsonParam::JsonParam(const ossimString& argname,
23  const ossimString& arglabel,
24  const ossimString& argdescr,
25  ParamType argparamType,
26  void* value)
27 : _name (argname),
28  _label (arglabel),
29  _descr (argdescr),
30  _type (argparamType),
31  _value(0)
32 {
33  setValue(value);
34 }
35 
37 : _label (copy._label),
38  _name (copy._name),
39  _descr (copy._descr),
40  _type (copy._type),
41  _value (0),
42  _allowedValues (copy._allowedValues)
43 {
44  setValue(copy._value);
45 }
46 
47 void JsonParam::setValue(void* value)
48 {
49  if (!value)
50  return;
51 
52  switch (_type)
53  {
54  case JsonParam::BOOL:
55  _value = new bool;
56  memcpy(_value, value, sizeof(bool));
57  break;
58  case JsonParam::INT:
59  _value = new int;
60  memcpy(_value, value, sizeof(int));
61  break;
62  case JsonParam::UINT:
63  _value = new unsigned int;
64  memcpy(_value, value, sizeof(unsigned int));
65  break;
66  case JsonParam::FLOAT:
67  _value = new double;
68  memcpy(_value, value, sizeof(double));
69  break;
70  case JsonParam::STRING:
71  _value = new string(*(string*)(value));
72  break;
73  case JsonParam::VECTOR:
74  _value = new vector<double>(*(vector<double>*)(value));
75  break;
76  default:
77  _value = 0;
78  }
79 }
80 
82 {
83  if (!_value)
84  return;
85 
86  switch (_type)
87  {
88  case JsonParam::BOOL:
89  delete (bool*)_value;
90  break;
91  case JsonParam::INT:
92  case JsonParam::UINT:
93  delete (int*)_value;
94  break;
95  case JsonParam::FLOAT:
96  delete (double*)_value;
97  break;
98  case JsonParam::STRING:
99  delete (string*)_value;
100  break;
101  case JsonParam::VECTOR:
102  ((vector<double>*)_value)->clear();
103  delete (vector<double>*)_value;
104  break;
105  default:
106  break;
107  }
108  _value = 0;
109 }
110 
111 bool JsonParam::loadJSON(const Json::Value& paramNode)
112 {
113  try
114  {
115  _name = paramNode["name"].asString();
116  _label = paramNode["label"].asString();
117  _descr = paramNode["descr"].asString();
118  Json::Value value = paramNode["value"];
119  Json::Value allowedValues = paramNode["allowedValues"];
120 
121  ossimString ptype = paramNode["type"].asString();
122  if (ptype.empty() || _name.empty())
123  return false;
124 
125  ptype.upcase();
126 
127  if (ptype == "VECTOR")
128  {
130  vector<double> v;
131  if (value.isArray())
132  {
133  int n = value.size();
134  for (unsigned int j=0; j<n; ++j)
135  v.push_back(value[j].asDouble());
136  }
137  setValue(&v);
138  }
139  else
140  {
141  // Screen for param value list as found in the default config JSONs. Pick the first element
142  // as the default:
143  if (value.isArray())
144  value = value[0];
145 
146  if (ptype == "BOOL")
147  {
149  bool v = value.asBool();
150  setValue(&v);
151  }
152  else if (ptype == "UINT")
153  {
155  unsigned int v = value.asUInt();
156  setValue(&v);
157  }
158  else if (ptype == "INT")
159  {
161  int v = value.asInt();
162  setValue(&v);
163  }
164  else if (ptype == "FLOAT")
165  {
167  double v = value.asDouble();
168  setValue(&v);
169  }
170  else if (ptype == "STRING")
171  {
173  string v = value.asString();
174  setValue(&v);
175  if (!allowedValues.empty() && allowedValues.isArray())
176  {
177  for (const auto &allowedValue : allowedValues)
178  _allowedValues.emplace_back(allowedValue.asString());
179  }
180  }
181  }
182  }
183  catch (exception& e)
184  {
185  ossimNotify(ossimNotifyLevel_WARN)<<"JsonParam::loadJSON() parse error encountered. Ignoring "
186  "but should check the JsonConfig JSON for parameter <"<<_name<<">."<<endl;
187  return false;
188  }
189  return true;
190 }
191 
192 void JsonParam::saveJSON(Json::Value& paramNode) const
193 {
194  vector<double>& v = *(vector<double>*)_value; // maybe not used since maybe not valid cast
195  unsigned int n = 0;
196  int i;
197  double f;
198  string s;
199  bool b;
200 
201  paramNode["name"] = _name.string();
202  paramNode["label"] = _label.string();
203  paramNode["descr"] = _descr.string();
204 
205  switch (_type)
206  {
207  case JsonParam::BOOL:
208  paramNode["type"] = "bool";
209  b = *(bool*)_value;
210  paramNode["value"] = b;
211  break;
212 
213  case JsonParam::INT:
214  paramNode["type"] = "int";
215  i = *(int*)_value;
216  paramNode["value"] = i;
217  break;
218 
219  case JsonParam::UINT:
220  paramNode["type"] = "uint";
221  n = *(unsigned int*)_value;
222  paramNode["value"] = n;
223  break;
224 
225  case JsonParam::FLOAT:
226  paramNode["type"] = "float";
227  f = *(double*)_value;
228  paramNode["value"] = f;
229  break;
230 
231  case JsonParam::STRING:
232  paramNode["type"] = "string";
233  s = *(string*)_value;
234  paramNode["value"] = s;
235  if (!_allowedValues.empty())
236  {
237  Json::Value allowedValues(Json::arrayValue);
238  for (const auto &allowedValue : _allowedValues)
239  allowedValues.append(allowedValue.c_str());
240  paramNode["allowedValues"] = allowedValues;
241  }
242  break;
243 
244  case JsonParam::VECTOR:
245  paramNode["type"] = "vector";
246  n = v.size();
247  for (unsigned int j=0; j<n; ++j)
248  paramNode["value"][j] = v[j];
249  break;
250 
251  case UNASSIGNED:
252  default:
253  break;
254  }
255 }
256 
257 bool JsonParam::asBool() const
258 {
259  if (_type == BOOL)
260  return *(bool*)_value;
261  return false;
262 }
263 
264 unsigned int JsonParam::asUint() const
265 {
266  if (_type == UINT)
267  return *(unsigned int*)_value;
268  return 0;
269 }
270 
271 int JsonParam::asInt() const
272 {
273  if ((_type == INT) || (_type == UINT))
274  return *(int*)_value;
275  return 0;
276 }
277 
278 double JsonParam::asFloat() const
279 {
280  if (_type == FLOAT)
281  return *(double*)_value;
282  return ossim::nan();
283 }
284 
285 std::string JsonParam::asString() const
286 {
287  if (_type == STRING)
288  return *(string*)_value;
289  return "";
290 }
291 
292 void JsonParam::asVector(std::vector<double>& v) const
293 {
294  v.clear();
295  if (_type == VECTOR)
296  v = *(vector<double>*)_value;
297 }
298 
300 {
301  Json::Value jsonNode;
302  obj.saveJSON(jsonNode);
303  out << jsonNode << endl;
304  return out;
305 }
306 
307 //-------------------------------------------------------------
308 
310 {
311  // This ctor could eventually curl a spring config server for the param JSON. For now it
312  // is reading the installed share/ossim system directory for config JSON files.
313 
314  // The previous parameters list is cleared first for a fresh start:
315  m_paramsMap.clear();
316  ossimFilename configFilename;
317  try
318  {
319  // First establish the directory location of the default config files:
321  preferencesKWL().findKey( std::string( "ossim_share_directory" )));
322  if (!shareName.isDir())
323  throw ossimException("Nonexistent share drive provided for config files.");
324 
325  // Fetch all JSON files:
326  ossimDirectory shareDir;
327  if (!shareDir.open(shareName))
328  throw ossimException("Share drive provided for config files is not readable.");
329  std::vector<ossimFilename> jsonFiles;
330  shareDir.findAllFilesThatMatch(jsonFiles, ".*\\.json");
331 
332  // Process those that contain the "parameters" JSON node:
333  for (unsigned int i=0; i<jsonFiles.size(); i++)
334  {
335  configFilename = jsonFiles[i];
336  if (!open(configFilename))
337  throw ossimException("Bad file open or parse.");
338  }
339 
340  }
341  catch (ossimException& e)
342  {
343  ossimNotify(ossimNotifyLevel_WARN)<<"JsonConfig::readConfig(): Could not open/parse "
344  "config file at <"<< configFilename << ">. Error: "<<e.what()<<endl;
345  }
346 }
347 
349 {
350  if (!open(configFile))
351  throw ossimException("Bad file open or parse.");
352 }
353 
355 {
356  m_paramsMap.clear();
357 }
358 
359 bool JsonConfig::open(const ossimFilename& configFileName)
360 {
361  ifstream configFile (configFileName.string());
362  if (configFile.fail())
363  return false;
364  Json::Value jsonRoot;
365  configFile >> jsonRoot;
366  if (jsonRoot.empty())
367  return false;
368  if (jsonRoot.isMember("parameters"))
369  {
370  Json::Value& paramsNode = jsonRoot["parameters"];
371  loadJSON(paramsNode);
372  }
373  configFile.close();
374  return true;
375 }
376 
377 JsonParam& JsonConfig::getParameter(const char* paramName)
378 {
379  map<string, JsonParam>::iterator i = m_paramsMap.find(string(paramName));
380  if (i != m_paramsMap.end())
381  return i->second;
382  return s_nullParam;
383 }
384 
386 {
387  // Tricky stuff to make sure it is a deep copy of the parameter:
388  string key = p.name().string();
389  std::map<std::string, JsonParam>::iterator iter = m_paramsMap.find(key);
390  if (iter != m_paramsMap.end())
391  m_paramsMap.erase(key);
392  m_paramsMap.emplace(key, p);
393 }
394 
395 bool JsonConfig::paramExists(const char* paramName) const
396 {
397  auto i = m_paramsMap.find(string(paramName));
398  if (i != m_paramsMap.end())
399  return true;
400  return false;
401 }
402 
403 void JsonConfig::loadJSON(const Json::Value& json_node)
404 {
405  // Support two forms: long (with full param descriptions and types), or short (just name: value)
406  if (json_node.isArray())
407  {
408  // Long form:
409  for (const auto &i : json_node)
410  {
411  JsonParam p;
412  if (p.loadJSON(i))
413  setParameter(p);
414  }
415  }
416  else
417  {
418  // Short form expects a prior entry in the params map whose value will be overriden here:
419  Json::Value::Members members = json_node.getMemberNames();
420  for (auto &member : members)
421  {
422  JsonParam& p = getParameter(member.c_str());
423  if (p.name().empty())
424  {
425  ossimNotify(ossimNotifyLevel_WARN)<<"JsonConfig::loadJSON(): Attempted to override "
426  "nonexistent parameter <"<< member << ">. Ignoring request."<<endl;
427  continue;
428  }
429  if (p.descr().contains("DEPRECATED"))
430  {
431  ossimNotify(ossimNotifyLevel_WARN)<<"JsonConfig::loadJSON() Parameter "<<p.name()
432  <<" "<<p.descr()<<endl;
433  continue;
434  }
435 
436  // Create a full JSON representation of the named parameter from the default list, replace
437  // its value, and recreate the parameter from the updated full JSON:
438  Json::Value paramNode;
439  p.saveJSON(paramNode);
440  paramNode["value"] = json_node[p.name().string()];
441  p.loadJSON(paramNode);
442  }
443  }
444 }
445 
446 
447 void JsonConfig::saveJSON(Json::Value& json_node) const
448 {
449 
450  map<string, JsonParam>::const_iterator param = m_paramsMap.begin();
451  int entry = 0;
452  while (param != m_paramsMap.end())
453  {
454  Json::Value paramNode;
455  param->second.saveJSON(paramNode);
456  json_node[entry++] = paramNode;
457  ++param;
458  }
459 }
460 
461 bool JsonConfig::diagnosticLevel(unsigned int level) const
462 {
463  map<string, JsonParam>::const_iterator i = m_paramsMap.find(string("diagnosticLevel"));
464  if (i != m_paramsMap.end())
465  {
466  unsigned int levelSetting = i->second.asUint();
467  return (level <= levelSetting);
468  }
469  return false;
470 }
471 
473 {
474  Json::Value configJsonNode;
475  obj.saveJSON(configJsonNode);
476  out<<configJsonNode<<endl;
477  return out;
478 }
479 
480 }
JsonParam & getParameter(const char *paramName)
Returns a parameter (might be a null parameter if paramName not found in the configuration.
Definition: JsonConfig.cpp:377
const ossimString & descr() const
Definition: JsonConfig.h:144
static ossimString upcase(const ossimString &aString)
Definition: ossimString.cpp:34
void setValue(void *value)
Definition: JsonConfig.cpp:47
JsonConfig()
Default Ctor loads all default .json files in the share/ossim system dir.
Definition: JsonConfig.cpp:309
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
This code was derived from https://gist.github.com/mshockwave.
Definition: Barrier.h:8
Base class for maintaining parameters affecting the runtime configuration of OSSIM executables...
Definition: JsonConfig.h:64
bool contains(char aChar) const
Definition: ossimString.h:58
double asFloat() const
Definition: JsonConfig.cpp:278
unsigned int asUint() const
Definition: JsonConfig.cpp:264
void asVector(std::vector< double > &v) const
Definition: JsonConfig.cpp:292
std::vector< ossimString > _allowedValues
Definition: JsonConfig.h:179
void findAllFilesThatMatch(std::vector< ossimFilename > &result, const ossimString &regularExpressionPattern, int flags=OSSIM_DIR_DEFAULT)
bool paramExists(const char *paramName) const
Definition: JsonConfig.cpp:395
bool isDir() const
ossimString _name
Definition: JsonConfig.h:174
virtual void saveJSON(Json::Value &params_json_node) const
Reads the params controlling the process from the JSON node named "parameters".
Definition: JsonConfig.cpp:447
std::map< std::string, JsonParam > m_paramsMap
Definition: JsonConfig.h:103
std::string asString() const
Definition: JsonConfig.cpp:285
Represents a single configuration parameter.
Definition: JsonConfig.h:112
void saveJSON(Json::Value &json_node) const
Definition: JsonConfig.cpp:192
virtual const char * what() const
Returns the error message.
os2<< "> n<< " > nendobj n
ParamType _type
Definition: JsonConfig.h:177
bool asBool() const
Definition: JsonConfig.cpp:257
const ossimString & name() const
Definition: JsonConfig.h:142
ossimString _label
Definition: JsonConfig.h:175
bool open(const ossimFilename &configFile)
Opens and parses JSON file. The "parameters" keyword is expected in the root node.
Definition: JsonConfig.cpp:359
static ossimPreferences * instance()
bool diagnosticLevel(unsigned int level) const
Convenience method returns TRUE if the currently set diagnostic level is <= level.
Definition: JsonConfig.cpp:461
bool open(const ossimFilename &dir)
bool loadJSON(const Json::Value &json_node)
Initializes from a JSON node.
Definition: JsonConfig.cpp:111
ostream & operator<<(std::ostream &out, const JsonParam &obj)
Definition: JsonConfig.cpp:299
bool empty() const
Definition: ossimString.h:411
ossimString _descr
Definition: JsonConfig.h:176
void setParameter(const JsonParam &p)
Adds parameter to the configuration.
Definition: JsonConfig.cpp:385
int asInt() const
Definition: JsonConfig.cpp:271
virtual void loadJSON(const Json::Value &params_json_node)
Reads the params controlling the process from the JSON node named "parameters".
Definition: JsonConfig.cpp:403
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
virtual ~JsonConfig()
Destructor.
Definition: JsonConfig.cpp:354
const std::string & string() const
Definition: ossimString.h:414
static JsonParam s_nullParam
Definition: JsonConfig.h:104