Skip to content

v0.2.52..v0.2.53 changeset Settings.cpp

Garret Voltz edited this page Feb 12, 2020 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/util/Settings.cpp b/hoot-core/src/main/cpp/hoot/core/util/Settings.cpp
index 5b1ad0e..d0c651f 100644
--- a/hoot-core/src/main/cpp/hoot/core/util/Settings.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/util/Settings.cpp
@@ -22,7 +22,7 @@
  * This will properly maintain the copyright information. DigitalGlobe
  * copyrights will be updated automatically.
  *
- * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/)
+ * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 DigitalGlobe (http://www.digitalglobe.com/)
  */
 
 #include "Settings.h"
@@ -32,7 +32,12 @@
 #include <hoot/core/util/ConfPath.h>
 #include <hoot/core/util/ConfigDefaults.h>
 #include <hoot/core/util/HootException.h>
+#include <hoot/core/util/ConfigOptions.h>
 #include <hoot/core/util/Log.h>
+#include <hoot/core/util/Factory.h>
+#include <hoot/core/ops/OsmMapOperation.h>
+#include <hoot/core/elements/ElementVisitor.h>
+#include <hoot/core/criterion/ElementCriterion.h>
 
 // Boost
 #include <boost/property_tree/ptree.hpp>
@@ -128,7 +133,7 @@ private:
     for (pt::ptree::value_type& element : tree.get_child(""))
     {
       const QString name = QString::fromUtf8(element.first.c_str());
-      LOG_VART(name);
+      //LOG_VART(name);
       //  Skip comments
       if (name.startsWith("#"))
         continue;
@@ -460,9 +465,72 @@ void Settings::loadJson(QString path)
   l.load(ConfPath::search(path));
 }
 
+void Settings::_validateOperatorRefs(const QStringList& operators)
+{
+  for (int i = 0; i < operators.size(); i++)
+  {
+    const QString operatorName = operators[i];
+    LOG_VART(operatorName);
+    const QString errorMsg = "Invalid option operator class name: " + operatorName;
+
+    if (!operatorName.startsWith("hoot::"))
+    {
+      throw IllegalArgumentException(errorMsg);
+    }
+
+    // Should either be a visitor, op, or criterion, but we don't know which one, so check for all
+    // of them.
+    std::shared_ptr<OsmMapOperation> op;
+    try
+    {
+      op.reset(Factory::getInstance().constructObject<OsmMapOperation>(operatorName));
+    }
+    catch (const boost::bad_any_cast&)
+    {
+    }
+    catch (const HootException&)
+    {
+    }
+
+    if (!op)
+    {
+      std::shared_ptr<ElementVisitor> vis;
+      try
+      {
+        vis.reset(Factory::getInstance().constructObject<ElementVisitor>(operatorName));
+      }
+      catch (const boost::bad_any_cast&)
+      {
+      }
+      catch (const HootException&)
+      {
+      }
+      if (!vis)
+      {
+        std::shared_ptr<ElementCriterion> crit;
+        try
+        {
+          crit.reset(Factory::getInstance().constructObject<ElementCriterion>(operatorName));
+        }
+        catch (const boost::bad_any_cast&)
+        {
+        }
+        catch (const HootException&)
+        {
+        }
+        if (!crit)
+        {
+          throw IllegalArgumentException(errorMsg);
+        }
+      }
+    }
+  }
+}
+
 void Settings::parseCommonArguments(QStringList& args)
 {
   LOG_DEBUG("Parsing command arguments...");
+  LOG_VART(args);
 
   bool foundOne = true;
 
@@ -483,7 +551,7 @@ void Settings::parseCommonArguments(QStringList& args)
   hootTestCmdsIgnore.append("--exclude");
 
   const QString optionInputFormatErrorMsg =
-    "define must takes the form key=value (or key+=value, key++=value, or key-=value).";
+    "define must take the form key=value (or key+=value, key++=value, or key-=value).";
 
   while (args.size() > 0 && foundOne)
   {
@@ -543,12 +611,14 @@ void Settings::parseCommonArguments(QStringList& args)
       {
         throw HootException(optionInputFormatErrorMsg);
       }
+
       QString kv = args[1];
-      // '++=' prepends an option to an option list
-      QStringList kvl = kv.split("++=");
       bool append = false;
       bool remove = false;
       bool prepend = true;
+
+      // '++=' prepends an option to an option list
+      QStringList kvl = kv.split("++=");
       if (kvl.size() != 2)
       {
         // '+=' appends an option to an option list
@@ -563,6 +633,7 @@ void Settings::parseCommonArguments(QStringList& args)
         remove = false;
         prepend = false;
       }
+
       if (kvl.size() != 2)
       {
         // '-=' removes an option from an option list
@@ -577,6 +648,7 @@ void Settings::parseCommonArguments(QStringList& args)
         remove = true;
         prepend = false;
       }
+
       if (kvl.size() != 2)
       {
         // split on the first '='
@@ -591,43 +663,66 @@ void Settings::parseCommonArguments(QStringList& args)
         remove = false;
         prepend = false;
       }
+      LOG_VART(append);
+      LOG_VART(remove);
+      LOG_VART(prepend);
+
       if (kvl.size() != 2)
       {
-        throw HootException(optionInputFormatErrorMsg);
+        throw IllegalArgumentException(optionInputFormatErrorMsg);
       }
-      if (!conf().hasKey(kvl[0]))
+
+      const QString optionName = kvl[0];
+      LOG_VART(optionName);
+      const QString optionVal = kvl[1];
+      LOG_VART(optionVal);
+
+      if (!conf().hasKey(optionName))
       {
-        throw HootException("Unknown settings option: (" + kvl[0] + ")");
+        throw IllegalArgumentException("Unknown settings option: (" + optionName + ")");
       }
+
+      const QStringList values = optionVal.split(";", QString::SkipEmptyParts);
+      LOG_VART(values);
+
+      // There are many more options that take class names as input than this. It would be
+      // difficult to validate all of them since they inherit from various base classes, so just
+      // starting with these more commonly used options whose values are classes that all inherit
+      // from ElementVisitor, OsmMapOperation, or ElementCriterion.
+      if (optionName == ConfigOptions::getConvertOpsKey() ||
+          optionName == ConfigOptions::getConflatePreOpsKey() ||
+          optionName == ConfigOptions::getConflatePostOpsKey())
+      {
+        _validateOperatorRefs(values);
+      }
+
       if (append)
       {
-        QStringList values = kvl[1].split(";", QString::SkipEmptyParts);
-        conf().append(kvl[0], values);
+        conf().append(optionName, values);
       }
       else if (remove)
       {
-        QStringList values = kvl[1].split(";", QString::SkipEmptyParts);
         foreach (QString v, values)
         {
-          QStringList newList = conf().getList(kvl[0]);
+          QStringList newList = conf().getList(optionName);
           if (!newList.contains(v))
           {
-            throw HootException("Unknown default value: (" + v + ")");
+            throw IllegalArgumentException("Option list does not contain value: (" + v + ")");
           }
           newList.removeAll(v);
-          conf().set(kvl[0], newList);
+          conf().set(optionName, newList);
         }
       }
       else if (prepend)
       {
-        QStringList values = kvl[1].split(";", QString::SkipEmptyParts);
-        conf().prepend(kvl[0], values);
+        conf().prepend(optionName, values);
       }
       else
       {
-        conf().set(kvl[0], kvl[1]);
+        conf().set(optionName, optionVal);
       }
-      // move on to the next argument.
+
+      // move on to the next argument
       args = args.mid(2);
     }
     else
@@ -635,6 +730,7 @@ void Settings::parseCommonArguments(QStringList& args)
       foundOne = false;
     }
   }
+
   // re-initialize the logger and other resources after the settings have been parsed.
   Hoot::getInstance().reinit();
 }
Clone this wiki locally