Просмотр исходного кода

Merge pull request #11184 from kenrowland/HPCC-19481

HPCC-19481 Add auto set of attribute values when adding new element

Reviewed-By: Rodrigo Pastrana <rodrigo.pastrana@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 7 лет назад
Родитель
Сommit
2cb0df5bad
32 измененных файлов с 1191 добавлено и 372 удалено
  1. 62 57
      configuration/config2/EnvironmentEventHandlers.cpp
  2. 33 15
      configuration/config2/EnvironmentEventHandlers.hpp
  3. 29 0
      configuration/config2/EnvironmentLoader.cpp
  4. 22 17
      configuration/config2/EnvironmentNode.cpp
  5. 5 5
      configuration/config2/EnvironmentValue.cpp
  6. 2 1
      configuration/config2/EnvironmentValue.hpp
  7. 9 7
      configuration/config2/InsertableItem.cpp
  8. 5 1
      configuration/config2/InsertableItem.hpp
  9. 2 2
      configuration/config2/SchemaItem.cpp
  10. 2 0
      configuration/config2/SchemaType.hpp
  11. 7 1
      configuration/config2/SchemaTypeLimits.cpp
  12. 10 0
      configuration/config2/SchemaTypeLimits.hpp
  13. 127 14
      configuration/config2/SchemaValue.cpp
  14. 24 10
      configuration/config2/SchemaValue.hpp
  15. 14 0
      configuration/config2/Status.cpp
  16. 1 0
      configuration/config2/Status.hpp
  17. 1 1
      configuration/config2/Utils.cpp
  18. 1 1
      configuration/config2/Utils.hpp
  19. 84 10
      configuration/config2/XSDSchemaParser.cpp
  20. 1 0
      configuration/config2/XSDSchemaParser.hpp
  21. 3 3
      configuration/config2/test.cpp
  22. 132 118
      esp/scm/ws_config2.ecm
  23. 34 6
      esp/services/ws_config2/ws_config2Service.cpp
  24. 5 1
      initfiles/componentfiles/config2xml/dali.xsd
  25. 32 40
      initfiles/componentfiles/config2xml/eclagent.xsd
  26. 26 26
      initfiles/componentfiles/config2xml/environment.xsd
  27. 3 2
      initfiles/componentfiles/config2xml/esp.xsd
  28. 32 14
      initfiles/componentfiles/config2xml/esp_service_smc.xsd
  29. 5 6
      initfiles/componentfiles/config2xml/esp_service_wsecl2.xsd
  30. 79 0
      initfiles/componentfiles/config2xml/ldapserver.xsd
  31. 346 0
      initfiles/componentfiles/config2xml/roxie.xsd
  32. 53 14
      initfiles/componentfiles/config2xml/types.xsd

+ 62 - 57
configuration/config2/EnvironmentEventHandlers.cpp

@@ -20,9 +20,50 @@ limitations under the License.
 #include "EnvironmentValue.hpp"
 
 
-bool CreateEnvironmentEventHandler::handleEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEventNode)
+void MatchEnvironmentEventHandler::processEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEventNode)
 {
-    return pEventNode->getSchemaItem()->getItemType() == m_itemType;
+    if (m_eventType == eventType && pEventNode->getSchemaItem()->getItemType() == m_itemType)
+    {
+        //
+        // If an event node attribute was defined, go check it
+        if (!m_eventNodeAttribute.empty())
+        {
+            //
+            // We need to check aginst an attribute in the event node. Build a list of comparison nodes using the
+            // target path
+            std::vector<std::shared_ptr<EnvironmentNode>> matchNodes;
+            pEventNode->fetchNodes(m_targetPath, matchNodes);
+            for (auto &nodeIt: matchNodes)
+            {
+                std::shared_ptr<EnvironmentValue> pItemAttr = pEventNode->getAttribute(m_targetAttribute);
+                if (pItemAttr)
+                {
+                    std::shared_ptr<EnvironmentValue> pMatchAttr =  nodeIt->getAttribute(m_targetAttribute);
+                    if (pMatchAttr)
+                    {
+                        if (pMatchAttr->getValue() == pItemAttr->getValue())
+                        {
+                            doHandleEvent(pEventNode);
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            doHandleEvent(pEventNode);
+        }
+    }
+}
+
+
+void MatchEnvironmentEventHandler::setEventNodeAttributeName(const std::string &name)
+{
+    m_eventNodeAttribute = name;
+    if (m_targetAttribute.empty())
+    {
+        m_targetAttribute = name;
+    }
 }
 
 
@@ -39,79 +80,43 @@ void AttributeDependencyCreateEventHandler::addDependency(const std::string &att
 }
 
 
-bool AttributeDependencyCreateEventHandler::handleEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEventNode)
+void AttributeDependencyCreateEventHandler::doHandleEvent(std::shared_ptr<EnvironmentNode> pEventNode)
 {
-    bool rc = false;
-    if (CreateEnvironmentEventHandler::handleEvent(eventType, pEventNode))
+    for (auto attrIt = m_depAttrVals.begin(); attrIt != m_depAttrVals.end(); ++attrIt)
     {
-        for (auto attrIt = m_depAttrVals.begin(); attrIt != m_depAttrVals.end(); ++attrIt)
+        std::shared_ptr<EnvironmentValue> pAttr = pEventNode->getAttribute(attrIt->first);
+        if (pAttr && pAttr->getSchemaValue()->getType()->isEnumerated())
         {
-            std::shared_ptr<EnvironmentValue> pAttr = pEventNode->getAttribute(attrIt->first);
-            if (pAttr && pAttr->getSchemaValue()->getType()->isEnumerated())
+            for (auto valueIt = attrIt->second.begin(); valueIt != attrIt->second.end(); ++valueIt)
             {
-                rc = true;   // we handled at least one
-                for (auto valueIt = attrIt->second.begin(); valueIt != attrIt->second.end(); ++valueIt)
-                {
-                    pAttr->getSchemaValue()->getType()->getLimits()->addDependentAttributeValue(valueIt->first, valueIt->second.first, valueIt->second.second);
-                }
+                pAttr->getSchemaValue()->getType()->getLimits()->addDependentAttributeValue(valueIt->first, valueIt->second.first, valueIt->second.second);
             }
         }
     }
-    return rc;
 }
 
 
-void InsertEnvironmentDataCreateEventHandler::setItemAttributeName(const std::string &name)
+void InsertEnvironmentDataCreateEventHandler::doHandleEvent(std::shared_ptr<EnvironmentNode> pEventNode)
 {
-    m_itemAttribute = name;
-    if (m_matchAttribute.empty())
-    {
-        m_matchAttribute = name;
-    }
+    pEventNode->addEnvironmentInsertData(m_envData);
 }
 
 
-bool InsertEnvironmentDataCreateEventHandler::handleEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEventNode)
+void AttributeSetValueCreateEventHandler::addAttributeValue(const std::string &attrName, const std::string &attrVal)
 {
-    bool rc = false;
-    if (CreateEnvironmentEventHandler::handleEvent(eventType, pEventNode))
-    {
-        if (!m_itemAttribute.empty())
-        {
-            std::vector<std::shared_ptr<EnvironmentNode>> matchNodes;
+    m_attrVals.push_back({attrName, attrVal});
+}
 
-            if (!m_matchPath.empty())
-            {
-                pEventNode->fetchNodes(m_matchPath, matchNodes);
-            }
-            else
-            {
-                matchNodes.push_back(pEventNode);
-            }
 
-            for (auto nodeIt = matchNodes.begin(); nodeIt != matchNodes.end(); ++nodeIt)
-            {
-                if (!m_itemAttribute.empty())
-                {
-                    std::shared_ptr<EnvironmentValue> pItemAttr = pEventNode->getAttribute(m_itemAttribute);
-                    if (pItemAttr)
-                    {
-                        std::shared_ptr<EnvironmentValue> pMatchAttr = (*nodeIt)->getAttribute(m_matchAttribute);
-                        if (pMatchAttr)
-                        {
-                            if (pMatchAttr->getValue() == pItemAttr->getValue())
-                            {
-                                pEventNode->addEnvironmentInsertData(m_envData);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        else
+void AttributeSetValueCreateEventHandler::doHandleEvent(std::shared_ptr<EnvironmentNode> pEventNode)
+{
+
+    for (auto &attrValPair : m_attrVals)
+    {
+        std::shared_ptr<EnvironmentValue> pAttr = pEventNode->getAttribute(attrValPair.first);
+        if (pAttr)
         {
-            pEventNode->addEnvironmentInsertData(m_envData);
+            pAttr->setValue(attrValPair.second, nullptr);
         }
     }
-    return rc;
 }

+ 33 - 15
configuration/config2/EnvironmentEventHandlers.hpp

@@ -22,6 +22,7 @@ limitations under the License.
 #include <string>
 #include <map>
 #include <memory>
+#include <vector>
 
 class EnvironmentNode;
 
@@ -31,7 +32,8 @@ class EnvironmentEventHandler
 
         EnvironmentEventHandler(const std::string &type) : m_eventType(type) {}
         virtual ~EnvironmentEventHandler() {}
-        virtual bool handleEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEnvNode) { return false; }
+        virtual void processEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEventNode) = 0;
+        virtual void doHandleEvent(std::shared_ptr<EnvironmentNode> pEventNode) = 0;
 
 
     protected:
@@ -40,31 +42,37 @@ class EnvironmentEventHandler
 };
 
 
-class CreateEnvironmentEventHandler : public EnvironmentEventHandler
+class MatchEnvironmentEventHandler : public EnvironmentEventHandler
 {
     public:
 
-        CreateEnvironmentEventHandler() : EnvironmentEventHandler("create") {}
-        virtual ~CreateEnvironmentEventHandler() {}
+        MatchEnvironmentEventHandler() : EnvironmentEventHandler("create") {}
+        virtual ~MatchEnvironmentEventHandler() {}
         void setItemType(const std::string &type) { m_itemType = type; }
+        void setEventNodeAttributeName(const std::string &name);
+        void setTargetAttributeName(const std::string &name) { m_targetAttribute = name; }
+        void setTargetPath(const std::string &path) { m_targetPath = path; }
 
-        virtual bool handleEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEnvNode);
+        virtual void processEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEventNode);
 
 
     protected:
 
         std::string m_itemType;
+        std::string m_targetPath;
+        std::string m_eventNodeAttribute;
+        std::string m_targetAttribute;
 };
 
 
-class AttributeDependencyCreateEventHandler : public CreateEnvironmentEventHandler
+class AttributeDependencyCreateEventHandler : public MatchEnvironmentEventHandler
 {
     public:
 
         AttributeDependencyCreateEventHandler() {}
         virtual ~AttributeDependencyCreateEventHandler() {}
         void addDependency(const std::string &attrName, const std::string &attrValr, const std::string &depAttr, const std::string &depVal);
-        virtual bool handleEvent(const std::string &eventType, std::shared_ptr<EnvironmentNode> pEnvNode);
+        virtual void doHandleEvent(std::shared_ptr<EnvironmentNode> pEventNode);
 
 
     protected:
@@ -73,25 +81,35 @@ class AttributeDependencyCreateEventHandler : public CreateEnvironmentEventHandl
 };
 
 
-class InsertEnvironmentDataCreateEventHandler : public CreateEnvironmentEventHandler
+class InsertEnvironmentDataCreateEventHandler : public MatchEnvironmentEventHandler
 {
     public:
 
         InsertEnvironmentDataCreateEventHandler() {}
         virtual ~InsertEnvironmentDataCreateEventHandler() {}
         void setEnvironmentInsertData(const std::string &envData) { m_envData = envData;  }
-        void setMatchPath(const std::string &path) { m_matchPath = path; }
-        void setItemAttributeName(const std::string &name);
-        void setMatchAttributeName(const std::string &name) { m_matchAttribute = name; }
-        virtual bool handleEvent(const std::string &envType, std::shared_ptr<EnvironmentNode> pEventNode);
+        virtual void doHandleEvent(std::shared_ptr<EnvironmentNode> pEventNode);
 
 
     protected:
 
         std::string m_envData;
-        std::string m_matchPath;
-        std::string m_itemAttribute;
-        std::string m_matchAttribute;
+};
+
+
+class AttributeSetValueCreateEventHandler : public MatchEnvironmentEventHandler
+{
+    public:
+
+        AttributeSetValueCreateEventHandler() {}
+        virtual ~AttributeSetValueCreateEventHandler() {}
+        void addAttributeValue(const std::string &attrName, const std::string &attrValr);
+        virtual void doHandleEvent(std::shared_ptr<EnvironmentNode> pEventNode);
+
+
+    protected:
+
+        std::vector<std::pair<std::string, std::string>> m_attrVals;
 };
 
 #endif

+ 29 - 0
configuration/config2/EnvironmentLoader.cpp

@@ -0,0 +1,29 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2018 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#include "EnvironmentLoader.hpp"
+#include "Exceptions.hpp"
+
+
+void EnvironmenLoader::addPath(const std::shared_ptr<EnvironmentNode> pNode)
+{
+    auto retVal = m_nodeIds.insert({pNode->getId(), pNode });
+    if (!retVal.second)
+    {
+        throw (ParseException("Attempted to insert duplicate path name " + pNode->getId() + " for node "));
+    }
+}

+ 22 - 17
configuration/config2/EnvironmentNode.cpp

@@ -318,12 +318,12 @@ void EnvironmentNode::getInsertableItems(std::vector<InsertableItem> &insertable
         {
             if (findIt->second < (*cfgIt)->getMaxInstances())
             {
-                insertableItems.push_back(InsertableItem(*cfgIt));
+                insertableItems.push_back(InsertableItem(shared_from_this(), *cfgIt));
             }
         }
         else
         {
-            insertableItems.push_back(InsertableItem(*cfgIt));
+            insertableItems.push_back(InsertableItem(shared_from_this(), *cfgIt));
         }
     }
 }
@@ -357,7 +357,7 @@ void EnvironmentNode::initialize()
 void EnvironmentNode::fetchNodes(const std::string &path, std::vector<std::shared_ptr<EnvironmentNode>> &nodes) const
 {
     //
-    // If path starts with / and we are not the root, get the root and do the fetch
+    // If path starts with / and we are not the root, get the root and do the find
     if (path[0] == '/')
     {
         std::string remainingPath = path.substr(1);
@@ -386,18 +386,20 @@ void EnvironmentNode::fetchNodes(const std::string &path, std::vector<std::share
         // Parent ?
         if (path[1] == '.')
         {
-            if (!m_pParent.expired())
+            //
+            // Path must be at least 4 characters in length to support the leading ../<remaining path>
+            if (!m_pParent.expired() && path.length() >= 4)
             {
-                m_pParent.lock()->fetchNodes(path.substr(2), nodes);
+                m_pParent.lock()->fetchNodes(path.substr(3), nodes);  // note skipping over '..'
             }
             else
             {
-                throw new ParseException("Attempt to navigate to parent with no parent");
+                throw new ParseException("Attempt to navigate to parent with no parent or path is incomplete");
             }
         }
         else
         {
-            fetchNodes(path.substr(1), nodes); // do the fetch from here stripping the '.' indicator
+            fetchNodes(path.substr(1), nodes); // do the find from here stripping the '.' indicator
         }
     }
 
@@ -406,7 +408,7 @@ void EnvironmentNode::fetchNodes(const std::string &path, std::vector<std::share
     else
     {
         std::string nodeName = path;
-        std::string remainingPath, attributeName, attributeValue;
+        std::string remainingPath, searchAttrName, searchAttrValue;
 
         //
         // Get our portion of the path which is up to the next / or the remaining string and
@@ -423,13 +425,13 @@ void EnvironmentNode::fetchNodes(const std::string &path, std::vector<std::share
         size_t atPos = nodeName.find_first_of('@');
         if (atPos != std::string::npos)
         {
-            attributeName = nodeName.substr(atPos + 1);
+            searchAttrName = nodeName.substr(atPos + 1);
             nodeName.erase(atPos, std::string::npos);
-            size_t equalPos = attributeName.find_first_of('=');
+            size_t equalPos = searchAttrName.find_first_of('=');
             if (equalPos != std::string::npos)
             {
-                attributeValue = attributeName.substr(equalPos + 1);
-                attributeName.erase(equalPos, std::string::npos);
+                searchAttrValue = searchAttrName.substr(equalPos + 1);
+                searchAttrName.erase(equalPos, std::string::npos);
             }
         }
 
@@ -440,21 +442,24 @@ void EnvironmentNode::fetchNodes(const std::string &path, std::vector<std::share
 
         //
         // If there is an attribute specified, dig deeper
-        if (!attributeName.empty())
+        if (!searchAttrName.empty())
         {
             auto childNodeIt = childNodes.begin();
             while (childNodeIt != childNodes.end())
             {
-                std::shared_ptr<EnvironmentValue> pValue = (*childNodeIt)->getAttribute(attributeName);
+                std::shared_ptr<EnvironmentValue> pValue = (*childNodeIt)->getAttribute(searchAttrName);
                 if (pValue)
                 {
-                    if (!attributeValue.empty() && pValue->getValue() != attributeValue)
+                    //
+                    // The attribute value must be present and, if necessary, must match the search value
+                    std::string curAttrValue = pValue->getValue();
+                    if (!curAttrValue.empty() && (searchAttrValue.empty() || (searchAttrValue == curAttrValue)))
                     {
-                        childNodeIt = childNodes.erase(childNodeIt);
+                        ++childNodeIt;  // keep it
                     }
                     else
                     {
-                        ++childNodeIt;
+                        childNodeIt = childNodes.erase(childNodeIt);
                     }
                 }
                 else

+ 5 - 5
configuration/config2/EnvironmentValue.cpp

@@ -93,19 +93,19 @@ void EnvironmentValue::validate(Status &status, const std::string &myId) const
 }
 
 
-// Called when a new value has been created, not read from existing environment, but created and added
 void EnvironmentValue::initialize()
 {
     //
-    // Is there an auto generated value we should process:
+    // Is there an auto generated value we should create?
     const std::string &type = m_pSchemaValue->getAutoGenerateType();
     if (!type.empty())
     {
         //
         // type "prefix" means to use the auto generate value as a name prefix and to append numbers until a new unique name is
-        // found
-        if (type == "prefix")
+        // found. ("prefix_" is a variation that adds an underbar (_) when appending numbers)
+        if (type == "prefix" || type=="prefix_")
         {
+            std::string connector = (type == "prefix_") ? "_" : "";
             std::string newName;
             const std::string &prefix = m_pSchemaValue->getAutoGenerateValue();
             std::vector<std::string> curValues;
@@ -128,7 +128,7 @@ void EnvironmentValue::initialize()
                     break;
                 }
                 ++n;
-                newName = prefix + std::to_string(n);
+                newName = prefix + connector + std::to_string(n);
             }
         }
 

+ 2 - 1
configuration/config2/EnvironmentValue.hpp

@@ -47,6 +47,7 @@ class DECL_EXPORT EnvironmentValue
         void validate(Status &status, const std::string &myId) const;
         void getAllValuesForSiblings(std::vector<std::string> &result) const;
         std::string getNodeId() const;
+        std::shared_ptr<EnvironmentNode> getEnvironmentNode() const { return m_pMyEnvNode.lock(); }
         void initialize();
 
     private:
@@ -58,4 +59,4 @@ class DECL_EXPORT EnvironmentValue
         std::weak_ptr<EnvironmentNode> m_pMyEnvNode;
 };
 
-#endif
+#endif

+ 9 - 7
configuration/config2/InsertableItem.cpp

@@ -16,20 +16,22 @@ limitations under the License.
 ############################################################################## */
 
 #include "InsertableItem.hpp"
+#include "EnvironmentNode.hpp"
 
-InsertableItem::InsertableItem(const std::shared_ptr<SchemaItem> &pSchemaItem) :
-    m_pSchemaItem(pSchemaItem)
-{
 
-    std::string insertLimitType = pSchemaItem->getProperty("insertLimitType");
+InsertableItem::InsertableItem(std::shared_ptr<const EnvironmentNode> pParentEnvNode, const std::shared_ptr<SchemaItem> &pSchemaItem) :
+    m_pParentEnvNode(pParentEnvNode), m_pSchemaItem(pSchemaItem), m_limitChoices(false)
+{
+    std::string insertLimitType = m_pSchemaItem->getProperty("insertLimitType");
     if (!insertLimitType.empty())
     {
+        m_limitChoices = true;
         if (insertLimitType == "attribute")
         {
-            std::string attributeName = pSchemaItem->getProperty("insertLimitData");
-            std::shared_ptr<SchemaValue> pSchemaValue = pSchemaItem->getAttribute(attributeName);
+            std::string attributeName = m_pSchemaItem->getProperty("insertLimitData");
+            std::shared_ptr<SchemaValue> pSchemaValue = m_pSchemaItem->getAttribute(attributeName);
             std::vector<AllowedValue> allowedValues;
-            pSchemaValue->getAllowedValues(allowedValues);
+            pSchemaValue->getAllowedValues(allowedValues, m_pParentEnvNode);
             for (auto &&av : allowedValues)
             {
                 m_itemLimits.push_back(InsertItemLimitChoice(av.m_value, attributeName, av.m_value));

+ 5 - 1
configuration/config2/InsertableItem.hpp

@@ -22,6 +22,8 @@ limitations under the License.
 #include "SchemaItem.hpp"
 #include <vector>
 
+class EnvironmentNode;
+
 struct InsertItemLimitChoice
 {
     InsertItemLimitChoice(const std::string &item, const std::string &attrName, const std::string &attrVal) :
@@ -34,9 +36,11 @@ struct InsertItemLimitChoice
 
 struct InsertableItem
 {
-    InsertableItem(const std::shared_ptr<SchemaItem> &pSchemaItem);
+    InsertableItem(std::shared_ptr<const EnvironmentNode> pParentEnvNode, const std::shared_ptr<SchemaItem> &pSchemaItem);
+    std::shared_ptr<const EnvironmentNode> m_pParentEnvNode;
     std::shared_ptr<SchemaItem> m_pSchemaItem;
     std::vector<InsertItemLimitChoice> m_itemLimits;
+    bool m_limitChoices;
 };
 
 #endif

+ 2 - 2
configuration/config2/SchemaItem.cpp

@@ -367,7 +367,7 @@ void SchemaItem::resetEnvironment()
 
 void SchemaItem::fetchSchemaValues(const std::string &path, std::vector<std::shared_ptr<SchemaValue>> &schemaValues)
 {
-    bool rootPath = path[0] == '/';
+    bool rootPath = path[0] == '/';   //todo: convert this to use the findSchemaRoot below
 
     //
     // If path is from the root, and we aren't the root, pass the request to our parent
@@ -584,7 +584,7 @@ void SchemaItem::processEvent(const std::string &eventType, const std::shared_pt
     // Loop through any event handlers we may have
     for (auto eventIt = m_eventHandlers.begin(); eventIt != m_eventHandlers.end(); ++eventIt)
     {
-        (*eventIt)->handleEvent(eventType, pEventSourceNode);
+        (*eventIt)->processEvent(eventType, pEventSourceNode);
     }
 
     //

+ 2 - 0
configuration/config2/SchemaType.hpp

@@ -44,6 +44,8 @@ class DECL_EXPORT SchemaType
         bool isEnumerated() const { return m_pLimits->isEnumerated(); }
         const std::vector<AllowedValue> getEnumeratedValues() const { return m_pLimits->getEnumeratedValues(); }
         const std::string getLimitString() const { return m_pLimits->getLimitString();  }
+        const std::string &getValidateMsg() const { return m_pLimits->getValidateMsg(); }
+        const std::string &getValidateMsgType() const { return m_pLimits->getValidateMsgType(); }
 
 
     private:

+ 7 - 1
configuration/config2/SchemaTypeLimits.cpp

@@ -25,6 +25,7 @@ std::vector<AllowedValue> SchemaTypeLimits::getEnumeratedValues() const
 
 bool SchemaTypeLimits::isValueValid(const std::string &testValue) const
 {
+    m_validateMsg = m_validateMsgType = "";
     bool rc = isValidEnumeratedValue(testValue);
     if (rc)
     {
@@ -42,7 +43,12 @@ bool SchemaTypeLimits::isValidEnumeratedValue(const std::string &testValue) cons
         rc = false;
         for (auto it = m_enumeratedValues.begin(); it != m_enumeratedValues.end() && !rc; ++it)
         {
-            rc = (testValue == (*it).m_value);
+            if (testValue == it->m_value)
+            {
+                rc = true;
+                m_validateMsg = it->m_userMessage;
+                m_validateMsgType = it->m_userMessageType;
+            }
         }
     }
     return rc;

+ 10 - 0
configuration/config2/SchemaTypeLimits.hpp

@@ -22,6 +22,7 @@
 #include <vector>
 #include <string>
 #include "platform.h"
+#include "Status.hpp"
 
 
 class EnvironmentValue;
@@ -37,12 +38,16 @@ struct DECL_EXPORT DependentValue
 
 struct DECL_EXPORT AllowedValue
 {
+    AllowedValue() {}
     AllowedValue(const std::string &value, const std::string &desc="") : m_value(value), m_displayName(value), m_description(desc) { }
     void addDependentValue(const std::string &attribute, const std::string &value);
     const std::vector<DependentValue> &getDependencies() const { return m_dependencies;  }
+    bool hasDependencies() const { return m_dependencies.size() > 0; }
     std::string m_displayName;
     std::string m_value;
     std::string m_description;
+    std::string m_userMessageType;
+    std::string m_userMessage;
     std::vector<DependentValue> m_dependencies;
 };
 
@@ -54,6 +59,7 @@ class DECL_EXPORT SchemaTypeLimits
         SchemaTypeLimits() { }
         virtual ~SchemaTypeLimits() { }
         void addAllowedValue(const std::string &value, const std::string &desc="") { m_enumeratedValues.push_back(AllowedValue(value, desc)); }
+        void addAllowedValue(const AllowedValue &val) { m_enumeratedValues.push_back(val); }
         void addDependentAttributeValue(const std::string &value, const std::string &depAttr, const std::string &depAttrVal);
         std::vector<AllowedValue> getEnumeratedValues() const;
         bool isEnumerated() const { return !m_enumeratedValues.empty(); }
@@ -63,6 +69,8 @@ class DECL_EXPORT SchemaTypeLimits
         virtual bool isMinSet() const { return false; }
         virtual int getMax() const { return 0; }
         virtual int getMin() const { return 0; }
+        const std::string &getValidateMsg() const { return m_validateMsg; }
+        const std::string &getValidateMsgType() const { return m_validateMsgType; }
 
 
     protected:
@@ -74,6 +82,8 @@ class DECL_EXPORT SchemaTypeLimits
     protected:
 
         std::vector<AllowedValue> m_enumeratedValues;
+        mutable std::string m_validateMsg;
+        mutable std::string m_validateMsgType;
 };
 
 

+ 127 - 14
configuration/config2/SchemaValue.cpp

@@ -17,6 +17,9 @@
 
 #include "SchemaValue.hpp"
 #include "EnvironmentValue.hpp"
+#include "EnvironmentNode.hpp"
+#include <algorithm>
+#include "Utils.hpp"
 
 SchemaValue::SchemaValue(const std::string &name, bool isDefined) :
     m_name(name), m_displayName(name)
@@ -38,12 +41,14 @@ SchemaValue::SchemaValue(const SchemaValue &value)
     m_mirrorFromPath = value.m_mirrorFromPath;
     m_autoGenerateValue = value.m_autoGenerateValue;
     m_autoGenerateType = value.m_autoGenerateType;
-    m_onChangeData = value.m_onChangeData;
-    m_onChangeType = value.m_onChangeType;
     bitMask = value.bitMask;
     m_default = value.m_default;
     m_tooltip = value.m_tooltip;
     m_modifiers = value.m_modifiers;
+    m_valueLimitRuleType = value.m_valueLimitRuleType;
+    m_valueLimitRuleData = value.m_valueLimitRuleData;
+    m_requiredIfSet = value.m_requiredIfSet;
+    m_group = value.m_group;
 
     // special processing? Maybe after inserting?
     std::vector<std::shared_ptr<SchemaValue>> m_mirrorToSchemaValues;
@@ -93,11 +98,35 @@ bool SchemaValue::isValueValid(const std::string &value, const EnvironmentValue
 void SchemaValue::validate(Status &status, const std::string &id, const EnvironmentValue *pEnvValue) const
 {
     std::string curValue = pEnvValue->getValue();
-    bool isValid;
+    bool isValid = m_pType->isValueValid(curValue);
 
-    if (!m_pType->isValueValid(curValue))
+    //
+    // If we have an environment value, more specific information can be provided
+    if (pEnvValue)
     {
-        if (pEnvValue)
+        //
+        // See if there is a dependency on another value being set.
+        if (!m_requiredIfSet.empty() && isValid)
+        {
+            //
+            // Required if set string format is path[@attribute[=value]]. Search this environment value's owning node
+            // for a match.
+            std::vector<std::shared_ptr<EnvironmentNode>> nodes;
+            pEnvValue->getEnvironmentNode()->fetchNodes(m_requiredIfSet, nodes);
+            if (!nodes.empty())
+            {
+                if (pEnvValue->getValue().empty())
+                {
+                    isValid = false;
+                    std::string msg = "Environment value required based on requiredIf rule " + m_requiredIfSet + " being set.";
+                    status.addMsg(statusMsg::error, pEnvValue->getNodeId(), pEnvValue->getName(), msg);
+                }
+            }
+        }
+
+        //
+        // If not valid, provide the reason
+        if (!isValid)
         {
             std::string msg;
             if (pEnvValue->wasForced())
@@ -108,7 +137,17 @@ void SchemaValue::validate(Status &status, const std::string &id, const Environm
 
             status.addMsg(pEnvValue->wasForced() ? statusMsg::warning : statusMsg::error, pEnvValue->getNodeId(), pEnvValue->getName(), msg);
         }
-        isValid = false;
+
+        //
+        // Otherwise, the value is valid, but there could be a validate message
+        else
+        {
+            const std::string &validateMsg = m_pType->getValidateMsg();
+            if (!validateMsg.empty())
+            {
+                status.addMsg(status.getMsgLevelFromString(m_pType->getValidateMsgType()), pEnvValue->getNodeId(), pEnvValue->getName(), validateMsg);
+            }
+        }
     }
 }
 
@@ -143,24 +182,95 @@ void SchemaValue::setMirroredEnvironmentValues(const std::string &oldValue, cons
 }
 
 
-void SchemaValue::getAllEnvironmentValues(std::vector<std::string> &values) const
+void SchemaValue::getAllEnvironmentValues(std::vector<std::shared_ptr<EnvironmentValue>> &envValues) const
 {
     for (auto it = m_envValues.begin(); it != m_envValues.end(); ++it)
     {
-        values.push_back((*it).lock()->getValue());
+        envValues.push_back(it->lock());
     }
 }
 
 
-void SchemaValue::getAllowedValues(std::vector<AllowedValue> &allowedValues, const EnvironmentValue *pEnvValue) const
+void SchemaValue::getAllowedValues(std::vector<AllowedValue> &allowedValues, const std::shared_ptr<const EnvironmentNode> &pEnvNode) const
 {
     //
-    // Either the type is enumerated, or there is a keyref.
+    // If enumerated, get the allowed values
     if (m_pType->isEnumerated())
     {
         allowedValues = m_pType->getEnumeratedValues();
     }
-    else if (isFromUniqueValueSet()) // && pEnvValue != nullptr)
+
+    //
+    // Is there a specialized rule that limits the values?
+    else if (!m_valueLimitRuleType.empty())
+    {
+        //
+        // uniqueItemType_1 - value is based on a unique item type described by the data for the rule. This is version 1
+        if (m_valueLimitRuleType == "uniqueItemType_1")
+        {
+            std::vector<std::string> params = splitString(m_valueLimitRuleData, ",");
+            std::vector<std::string> parts;
+
+            //
+            // First parameter is the source values for an attribute search. The two parts of the parameter are the path to the
+            // node set where the atttribute, the second part, name is found (not that there may be no entries). Find all the nodes
+            // for the path (parts[0]), then get all of the values for the attribute (parts[1]). This serves as the list of existing
+            // values that are eliminated from the final list of allowable values.
+            parts = splitString(params[0], "@");
+            std::vector<std::shared_ptr<EnvironmentNode>> existingSourceNodes;
+            pEnvNode->fetchNodes(parts[0], existingSourceNodes);
+            std::vector<std::string> existingSourceAttributeValues;
+            for (auto &existingNodeIt: existingSourceNodes)
+            {
+                existingSourceAttributeValues.push_back( existingNodeIt->getAttributeValue(parts[1]));
+            }
+
+            //
+            // Get the full set of possible values using the params[1] values. From its parts, parts[0] is the path
+            // to find the set of all possible nodes that could serve as an allowable value.
+            std::vector<std::shared_ptr<EnvironmentNode>> allSourceNodes;
+            parts = splitString(params[1], "@");
+            std::string sourceAttributeName = parts[1];  // for use below in case parts is reused later
+            pEnvNode->fetchNodes(parts[0], allSourceNodes);
+
+            //
+            // For each exising source node, using the existingSourceAttributeValues, matching the name to the value in
+            // sourceAttributeName, and collect the itemType values found.
+            std::vector<std::string> existingItemTypes;
+            for (auto &existingValueIt: existingSourceAttributeValues)
+            {
+                std::vector<std::shared_ptr<EnvironmentNode>>::iterator sourceIt = std::find_if(allSourceNodes.begin(), allSourceNodes.end(),
+                    [&](std::shared_ptr<EnvironmentNode> &srcIt) {
+                        return srcIt->getAttributeValue(sourceAttributeName) == existingValueIt;
+                });
+
+                if (sourceIt != allSourceNodes.end())
+                {
+                    existingItemTypes.push_back((*sourceIt)->getSchemaItem()->getItemType());
+                }
+            }
+
+            //
+            // Build the allowable value list by only adding itmes from the all sources list that don't hvae
+            // an entry in the existing item type vector
+            for (auto &sourceIt: allSourceNodes)
+            {
+                std::vector<std::string>::const_iterator itemTypeIt = std::find_if(existingItemTypes.begin(), existingItemTypes.end(), [&](const std::string &itemIt) {
+                    return itemIt == sourceIt->getSchemaItem()->getItemType();
+                });
+
+                if (itemTypeIt == existingItemTypes.end())
+                {
+                    allowedValues.push_back({ sourceIt->getAttributeValue(sourceAttributeName), "" });
+                }
+            }
+        }
+    }
+
+    //
+    // Or, keyed? (note that the keyed check MUST be last since a more restrictive rule may be defined for UI purposes
+    // while a keyed reference is present for XML schema validation)
+    else if (isFromUniqueValueSet())
     {
         std::vector<std::string> refValues;
         getAllKeyRefValues(refValues);
@@ -178,8 +288,11 @@ void SchemaValue::getAllKeyRefValues(std::vector<std::string> &keyRefValues) con
     for (auto refCfgValueIt = refCfgValues.begin(); refCfgValueIt != refCfgValues.end(); ++refCfgValueIt)
     {
         std::shared_ptr<SchemaValue> pRefCfgValue = (*refCfgValueIt).lock();
-        std::vector<std::string> allValues;
-        pRefCfgValue->getAllEnvironmentValues(allValues);
-        keyRefValues.insert(keyRefValues.end(), allValues.begin(), allValues.end());
+        std::vector<std::shared_ptr<EnvironmentValue>> allEnvValues;
+        pRefCfgValue->getAllEnvironmentValues(allEnvValues);
+        for (auto &envIt: allEnvValues)
+        {
+            keyRefValues.push_back(envIt->getValue());
+        }
     }
 }

+ 24 - 10
configuration/config2/SchemaValue.hpp

@@ -23,6 +23,8 @@
 #include "Status.hpp"
 #include "platform.h"
 
+class EnvironmentNode;
+
 
 class DECL_EXPORT SchemaValue
 {
@@ -67,24 +69,30 @@ class DECL_EXPORT SchemaValue
         void addMirroredSchemaValue(const std::shared_ptr<SchemaValue> &pVal) { m_mirrorToSchemaValues.push_back(pVal); }
         void mirrorValueToEnvironment(const std::string &oldValue, const std::string &newValue);
         void addEnvironmentValue(const std::shared_ptr<EnvironmentValue> &pEnvValue) { m_envValues.push_back(pEnvValue); }
-        void getAllEnvironmentValues(std::vector<std::string> &values) const;
+        void getAllEnvironmentValues(std::vector<std::shared_ptr<EnvironmentValue>> &envValues) const;
         void setMirroredEnvironmentValues(const std::string &oldValue, const std::string &newValue);
         void validate(Status &status, const std::string &id, const EnvironmentValue *pEnvValue = nullptr) const;
-        void getAllowedValues(std::vector<AllowedValue> &allowedValues, const EnvironmentValue *pEnvValue = nullptr) const;
+        void getAllowedValues(std::vector<AllowedValue> &allowedValues, const std::shared_ptr<const EnvironmentNode> &pEnvNode) const;
         void setAutoGenerateType(const std::string &type) { m_autoGenerateType = type; }
         const std::string &getAutoGenerateType() const { return m_autoGenerateType; }
         void setAutoGenerateValue(const std::string &value) { m_autoGenerateValue = value; }
         const std::string &getAutoGenerateValue() const { return m_autoGenerateValue; }
         void getAllKeyRefValues(std::vector<std::string> &keyRefValues) const;
-        void setOnChangeType(const std::string &type) { m_onChangeType = type;  }
-        const std::string &getOnChangeType() const { return m_onChangeType;  }
-        bool isOnChangeSet() const { return !m_onChangeType.empty(); }
-        void setOnChangeData(const std::string &data) { m_onChangeData = data; }
-        const std::string &getOnChangeData() const { return m_onChangeData;  }
+        void setCodeDefault(const std::string &value) { m_codeDefault = value; }
+        const std::string &getCodeDefault() const { return m_codeDefault; }
+        void setValueLimitRuleType(const std::string &type) { m_valueLimitRuleType = type; }
+        const std::string &getValueLimitRuleType() { return m_valueLimitRuleType; }
+        void setValueLimitRuleData(const std::string &data) { m_valueLimitRuleData = data; }
+        const std::string &getValueLimitRuleData() { return m_valueLimitRuleData; }
+        void setRequiredIfSet(const std::string &reqIf) { m_requiredIfSet = reqIf; }
+        const std::string &getRequiredIfSet() const { return m_requiredIfSet; }
+        void setGroup(const std::string &group) { m_group = group; }
+        const std::string &getGroup() const { return m_group; }
 
 
     protected:
 
+        // DON'T FORGET IF DATA ADDED, IT MAY MAY TO BE COPIED IN THE COPY CONSTRUCTOR!!
         std::shared_ptr<SchemaType> m_pType;
         std::vector<std::weak_ptr<EnvironmentValue>> m_envValues;
         std::vector<std::shared_ptr<SchemaValue>> m_mirrorToSchemaValues;
@@ -93,8 +101,11 @@ class DECL_EXPORT SchemaValue
         std::string m_mirrorFromPath;
         std::string m_autoGenerateValue;
         std::string m_autoGenerateType;
-        std::string m_onChangeType;
-        std::string m_onChangeData;
+        std::string m_valueLimitRuleType;
+        std::string m_valueLimitRuleData;
+        std::string m_requiredIfSet;
+        std::string m_group;
+        // DON'T FORGET IF DATA ADDED, IT MAY MAY TO BE COPIED IN THE COPY CONSTRUCTOR!!
 
         struct {
             unsigned m_required  : 1;
@@ -105,10 +116,13 @@ class DECL_EXPORT SchemaValue
             unsigned m_isDefined : 1;
         } bitMask;
 
-        std::string m_default;
+        // DON'T FORGET IF DATA ADDED, IT MAY MAY TO BE COPIED IN THE COPY CONSTRUCTOR!!
+        std::string m_default;        // value written to environment if no user value supplied
+        std::string m_codeDefault;    // informational value nform user code default if no value supplied
         std::string m_tooltip;
         std::vector<std::string> m_modifiers;
         std::vector<std::weak_ptr<SchemaValue>> m_pUniqueValueSetRefs;    // this value serves as the key from which values are valid
+        // DON'T FORGET IF DATA ADDED, IT MAY MAY TO BE COPIED IN THE COPY CONSTRUCTOR!!
 };
 
 #endif // _CONFIG2_VALUE_HPP_

+ 14 - 0
configuration/config2/Status.cpp

@@ -64,6 +64,20 @@ std::string Status::getStatusTypeString(enum statusMsg::msgLevel status) const
     return result;
 }
 
+
+enum statusMsg::msgLevel Status::getMsgLevelFromString(const std::string &status) const
+{
+    enum statusMsg::msgLevel lvl;
+    if (status == "info")          { lvl = statusMsg::info;     }
+    else if (status == "warning")  { lvl = statusMsg::warning;  }
+    else if (status == "error")    { lvl = statusMsg::error;    }
+    else if (status == "fatal")    { lvl = statusMsg::fatal;    }
+    else                           { lvl = statusMsg::fatal;    }
+
+    return lvl;
+}
+
+
 void Status::add(const std::vector<statusMsg> msgs)
 {
     for (auto msgIt = msgs.begin(); msgIt != msgs.end(); ++msgIt)

+ 1 - 0
configuration/config2/Status.hpp

@@ -57,6 +57,7 @@ class DECL_EXPORT Status
         bool isOk() const { return m_highestMsgLevel <= statusMsg::warning; }
         bool isError() const { return m_highestMsgLevel >= statusMsg::error; }
         std::string getStatusTypeString(enum statusMsg::msgLevel status) const;
+        enum statusMsg::msgLevel getMsgLevelFromString(const std::string &status) const;
         std::vector<statusMsg> getMessages() const;
         void add(const std::vector<statusMsg> msgs);
 

+ 1 - 1
configuration/config2/Utils.cpp

@@ -18,7 +18,7 @@ limitations under the License.
 #include <vector>
 #include <string>
 
-std::vector<std::string> splitString(const std::string  &input, const std::string  &delim)
+std::vector<std::string> splitString(const std::string  &input, const std::string delim)
 {
     size_t  start = 0, end = 0, delimLen = delim.length();
     std::vector<std::string> list;

+ 1 - 1
configuration/config2/Utils.hpp

@@ -21,6 +21,6 @@ limitations under the License.
 
 #include <vector>
 
-std::vector<std::string> splitString(const std::string  &input, const std::string  &delim);
+std::vector<std::string> splitString(const std::string  &input, const std::string delim);
 
 #endif

+ 84 - 10
configuration/config2/XSDSchemaParser.cpp

@@ -322,6 +322,7 @@ void XSDSchemaParser::parseElement(const pt::ptree &elemTree)
         if (!insertLimitData.empty()) pNewSchemaItem->setProperty("insertLimitData", insertLimitData);
         pNewSchemaItem->setMinInstances(minOccurs);
         pNewSchemaItem->setMaxInstances(maxOccurs);
+        pNewSchemaItem->setHidden(elemTree.get("<xmlattr>.hpcc:hidden", "false") == "true");
 
         //
         // Type specified?
@@ -434,6 +435,18 @@ void XSDSchemaParser::parseAppInfo(const pt::ptree &elemTree)
                         std::string depVal = getXSDAttributeValue(it->second, "<xmlattr>.dependentValue");
                         pDep->addDependency(attrName, attrVal, depAttr, depVal);
                     }
+                    else if (it->first == "match")
+                    {
+                        std::string attrName = it->second.get("eventNodeAttribute", "").data();
+                        pDep->setEventNodeAttributeName(attrName);
+                        std::string matchAttrName = it->second.get("targetAttribute", "");
+                        if (!matchAttrName.empty())
+                        {
+                            pDep->setTargetAttributeName(matchAttrName);
+                        }
+                        std::string path = it->second.get("targetPath", "");
+                        pDep->setTargetPath(path);
+                    }
                 }
                 m_pSchemaItem->addEventHandler(pDep);
             }
@@ -467,15 +480,15 @@ void XSDSchemaParser::parseAppInfo(const pt::ptree &elemTree)
                     //                          matchItemAttribute
                     else if (it->first == "match")
                     {
-                        std::string attrName = it->second.get("matchItemAttribute", "").data();
-                        pInsert->setItemAttributeName(attrName);
-                        std::string matchAttrName = it->second.get("matchLocalAttribute", "");
+                        std::string attrName = it->second.get("eventNodeAttribute", "").data();
+                        pInsert->setEventNodeAttributeName(attrName);
+                        std::string matchAttrName = it->second.get("targetAttribute", "");
                         if (!matchAttrName.empty())
                         {
-                            pInsert->setMatchAttributeName(matchAttrName);
+                            pInsert->setTargetAttributeName(matchAttrName);
                         }
-                        std::string path = it->second.get("matchPath", "");
-                        pInsert->setMatchPath(path);
+                        std::string path = it->second.get("targetPath", "");
+                        pInsert->setTargetPath(path);
                     }
 
                     //
@@ -492,6 +505,40 @@ void XSDSchemaParser::parseAppInfo(const pt::ptree &elemTree)
                 }
                 m_pSchemaItem->addEventHandler(pInsert);
             }
+
+            //
+            // addAttributeDependencies is used to set dependent values for an attribute based on the value of another attribute.
+            else if (eventAction == "setAttributeValue")
+            {
+                std::shared_ptr<AttributeSetValueCreateEventHandler> pSetAttrValue = std::make_shared<AttributeSetValueCreateEventHandler>();
+                pt::ptree dataTree = childTree.get_child("eventData", emptyTree);
+                for (auto it = dataTree.begin(); it != dataTree.end(); ++it)
+                {
+                    if (it->first == "itemType")
+                    {
+                        pSetAttrValue->setItemType(it->second.data());
+                    }
+                    else if (it->first == "attribute")
+                    {
+                        std::string attrName = getXSDAttributeValue(it->second, "<xmlattr>.attributeName");
+                        std::string attrVal = getXSDAttributeValue(it->second, "<xmlattr>.attributeValue");
+                        pSetAttrValue->addAttributeValue(attrName, attrVal);
+                    }
+                    else if (it->first == "match")
+                    {
+                        std::string attrName = it->second.get("eventNodeAttribute", "").data();
+                        pSetAttrValue->setEventNodeAttributeName(attrName);
+                        std::string matchAttrName = it->second.get("targetAttribute", "");
+                        if (!matchAttrName.empty())
+                        {
+                            pSetAttrValue->setTargetAttributeName(matchAttrName);
+                        }
+                        std::string path = it->second.get("targetPath", "");
+                        pSetAttrValue->setTargetPath(path);
+                    }
+                }
+                m_pSchemaItem->addEventHandler(pSetAttrValue);
+            }
         }
     }
 }
@@ -558,7 +605,7 @@ void XSDSchemaParser::parseIntegerTypeLimits(const pt::ptree &restrictTree, std:
             pIntegerLimits->setMaxExclusive(it->second.get<int>("<xmlattr>.value"));
         else if (restrictionType == "xs:enumeration")
         {
-            pIntegerLimits->addAllowedValue(it->second.get("<xmlattr>.value", "badbadbad"), it->second.get("<xmlattr>.hpcc:description", ""));
+            parseAllowedValue(it->second, &(*pIntegerLimits));
         }
         else if (restrictionType != "<xmlattr>")
         {
@@ -585,7 +632,7 @@ void XSDSchemaParser::parseStringTypeLimits(const pt::ptree &restrictTree, std::
             pStringLimits->addPattern(it->second.get("<xmlattr>.value", "0"));
         else if (restrictionType == "xs:enumeration")
         {
-            pStringLimits->addAllowedValue(it->second.get("<xmlattr>.value", "badbadbad"), it->second.get("<xmlattr>.hpcc:description", ""));
+            parseAllowedValue(it->second, &(*pStringLimits));
         }
         else if (restrictionType != "<xmlattr>")
         {
@@ -596,6 +643,31 @@ void XSDSchemaParser::parseStringTypeLimits(const pt::ptree &restrictTree, std::
 }
 
 
+void XSDSchemaParser::parseAllowedValue(const pt::ptree &allowedValueTree, SchemaTypeLimits *pTypeLimits)
+{
+    AllowedValue allowedValue;
+
+    //
+    // Parse the value for the enumeration, the add to the allowed values for the limits for this type. Note that enumerations
+    // are enhanced with additional information for the UI.
+    allowedValue.m_value = allowedValueTree.get("<xmlattr>.value", "");
+    allowedValue.m_displayName = allowedValueTree.get("<xmlattr>.hpcc:displayName", allowedValue.m_value);
+    allowedValue.m_description = allowedValueTree.get("<xmlattr>.hpcc:description", "");
+    allowedValue.m_userMessage = allowedValueTree.get("<xmlattr>.hpcc:userMessage", "");
+    allowedValue.m_userMessageType = allowedValueTree.get("<xmlattr>.hpcc:userMessageType", allowedValue.m_userMessage.empty() ? "" : "info");
+
+    //
+    // Value is required. Throw an exception if not found
+    if (allowedValue.m_value.empty())
+    {
+        std::string msg = "Missing value attribute for enumeration";
+        throw(ParseException(msg));
+    }
+
+    pTypeLimits->addAllowedValue(allowedValue);
+}
+
+
 std::shared_ptr<SchemaValue> XSDSchemaParser::getSchemaValue(const pt::ptree &attr)
 {
     std::string attrName = getXSDAttributeValue(attr, "<xmlattr>.name");
@@ -610,8 +682,10 @@ std::shared_ptr<SchemaValue> XSDSchemaParser::getSchemaValue(const pt::ptree &at
     pCfgValue->setAutoGenerateType(attr.get("<xmlattr>.hpcc:autoGenerateType", ""));
     pCfgValue->setAutoGenerateValue(attr.get("<xmlattr>.hpcc:autoGenerateValue", ""));
     pCfgValue->setDefaultValue(attr.get("<xmlattr>.default", ""));
-    pCfgValue->setOnChangeType(attr.get("<xmlattr>.hpcc:onChangeType", ""));
-    pCfgValue->setOnChangeData(attr.get("<xmlattr>.hpcc:onChangeData", ""));
+    pCfgValue->setCodeDefault(attr.get("<xmlattr>.hpcc:codeDefault", ""));
+    pCfgValue->setValueLimitRuleType(attr.get("<xmlattr>.hpcc:valueLimitRuleType", ""));
+    pCfgValue->setValueLimitRuleData(attr.get("<xmlattr>.hpcc:valueLimitRuleData", ""));
+    pCfgValue->setRequiredIfSet(attr.get("<xmlattr>.hpcc:requiredIfSet", ""));
 
     std::string modList = attr.get("<xmlattr>.hpcc:modifiers", "");
     if (modList.length())

+ 1 - 0
configuration/config2/XSDSchemaParser.hpp

@@ -63,6 +63,7 @@ class XSDSchemaParser : public SchemaParser
         virtual void parseKeyRef(const pt::ptree &keyTree);
         virtual void parseIntegerTypeLimits(const pt::ptree &restrictTree, std::shared_ptr<SchemaTypeIntegerLimits> &pIntegerLimits);
         virtual void parseStringTypeLimits(const pt::ptree &restrictTree, std::shared_ptr<SchemaTypeStringLimits> &pStringLimits);
+        virtual void parseAllowedValue(const pt::ptree &allowedValueTree, SchemaTypeLimits *pTypeLimits);
 
     protected:
 

+ 3 - 3
configuration/config2/test.cpp

@@ -47,7 +47,7 @@ int main()
         pEnvMgr->loadEnvironment(c_path + "/environment.xml");
 
         std::vector<std::shared_ptr<EnvironmentNode>> nodes;
-        pEnvMgr->findNodes("/Environment/Software/EspService@buildSet=espsmc", nodes);
+        pEnvMgr->fetchNodes("/Environment/Software/EspService@buildSet=espsmc", nodes);
 
         // 158
         //auto pNode = envMgr.getNodeFromPath("158");
@@ -59,7 +59,7 @@ int main()
         //auto list = pNode->getInsertableItems();
 
         Status status;
-        auto pNewNode = pEnvMgr->addNewEnvironmentNode("108", "espsmc", status);
+        //auto pNewNode = pEnvMgr->addNewEnvironmentNode("108", "espsmc", status);
         //auto newList = pNewNode->getInsertableItems();
         //pEnvMgr->addNewEnvironmentNode("35", "ws_ecl", status);
         //pEnvMgr->addNewEnvironmentNode("35", "ws_ecl", status);
@@ -82,7 +82,7 @@ int main()
 
 
         Status status2;
-        pNewNode = pEnvMgr->addNewEnvironmentNode("138", "espbinding@service=EclWatch1", status2);  // todo: when valildating, look at required flag first
+        //pNewNode = pEnvMgr->addNewEnvironmentNode("138", "espbinding@service=EclWatch1", status2);  // todo: when valildating, look at required flag first
 
 
         /*auto attributes = pNode->getAttributes();

+ 132 - 118
esp/scm/ws_config2.ecm

@@ -18,18 +18,18 @@
 
 ESPstruct StatusMsgType
 {
-    string msgLevel;                // message level ("info", "warning", "error", "fatal")
-    string nodeId;                  // node identifier that generated this status message
-    string nodeName("");            // node name (not unique, use nodeID to retrieve node)
-    string attribute("");           // name of node's attribute generating the message ("" for the node itself)
-    string msg;                     // the message
-    ESParray<string, parentId> parentIdList;
+    string MsgLevel;                // message level ("info", "warning", "error", "fatal")
+    string NodeId;                  // node identifier that generated this status message
+    string NodeName("");            // node name (not unique, use nodeID to find node)
+    string Attribute("");           // name of node's attribute generating the message ("" for the node itself)
+    string Msg;                     // the message
+    ESParray<string, parentId> ParentIdList;
 };
 
 ESPstruct StatusType
 {
-    bool error(false);    // true if a message exsits in status (below) with a message level of error or higher
-    ESParray<ESPstruct StatusMsgType, StatusMsg> status;
+    bool Error(false);    // true if a message exsits in status (below) with a message level of error or higher
+    ESParray<ESPstruct StatusMsgType, StatusMsg> Status;
 };
 
 
@@ -40,7 +40,7 @@ ESPresponse [exceptions_inline] EmptyResponse
 
 ESPresponse StatusResponse
 {
-    ESPstruct StatusType status;
+    ESPstruct StatusType Status;
 };
 
 
@@ -49,24 +49,24 @@ ESPresponse StatusResponse
 
 ESPrequest OpenSessionRequest
 {
-    string username;
-    string schemaPath("");        // location of configuration schema environmentFiles
-    string masterSchemaFile("");  // name of master schema control file
-    string sourcePath("");        // path to envrionment files
-    string activePath("");        // path to active environment file ("" for none)
+    string Username;
+    string SchemaPath("");        // location of configuration schema environmentFiles
+    string MasterSchemaFile("");  // name of master schema control file
+    string SourcePath("");        // path to envrionment files
+    string ActivePath("");        // path to active environment file ("" for none)
 };
 
 
 ESPresponse [exceptions_inline] OpenSessionResponse
 {
-    string sessionId;
+    string SessionId;
 };
 
 
 ESPrequest CloseSessionRequest
 {
-    string sessionId;
-    bool forceClose(false);    // set to true for force the closure of a modified environment w/o saving
+    string SessionId;
+    bool   ForceClose(false);    // set to true for force the closure of a modified environment w/o saving
 };
 
 
@@ -77,16 +77,16 @@ ESPrequest ListOpenSessionsRequest
 
 ESPstruct OpenSessionInfo
 {
-    string username;
-    string curEnvironmentFile("");
-    bool   locked;
-    bool   modified;
+    string Username;
+    string CurEnvironmentFile("");
+    bool   Locked;
+    bool   Modified;
 };
 
 
 ESPresponse [exceptions_inline] ListOpenSessionsResponse
 {
-    ESParray<ESPstruct OpenSessionInfo, SessionInfo> openSessions;
+    ESParray<ESPstruct OpenSessionInfo, SessionInfo> OpenSessions;
 };
 
 
@@ -95,142 +95,156 @@ ESPresponse [exceptions_inline] ListOpenSessionsResponse
 
 ESPrequest NodeRequest
 {
-    string sessionId;
-    string nodeId;
+    string SessionId;
+    string NodeId;
 };
 
 
 ESPrequest RemoveNodeRequest
 {
-    string sessionId;
-    string sessionLockKey;
-    string nodeId;
+    string SessionId;
+    string SessionLockKey;
+    string NodeId;
+};
+
+
+ESPstruct DependentValueType
+{
+    string AttributeName;
+    string AttributeValue;
 };
 
 
 ESPstruct ChoiceType
 {
-    string displayName;
-    string value;
-    string desc("");
+    string DisplayName;
+    string Value;
+    string Desc("");
+    string MsgType("");
+    string Msg("");
+    ESParray<ESPstruct DependentValueType, dependentValue> Dependencies;
 };
 
 
+
 ESPstruct LimitsType
 {
-    bool   minValid(false);
-    bool   maxValid(false);
-    int    min(0);
-    int    max(0);
-    ESParray<ESPstruct ChoiceType, Choice> choiceList;
-    ESParray<string, Expr> regex;
+    bool   MinValid(false);
+    bool   MaxValid(false);
+    int    Min(0);
+    int    Max(0);
+    ESParray<ESPstruct ChoiceType, Choice> ChoiceList;
+    ESParray<string, Expr> Regex;
 };
 
 
 ESPstruct TypeInfo
 {
-    string name;
-    ESPstruct LimitsType limits;
-    ESParray<string, Modifier> modifiers;
+    string Name;
+    ESPstruct LimitsType Limits;
+    ESParray<string, Modifier> Modifiers;
 };
 
 
 ESPstruct NodeInfoType
 {
-    string    name("");
-    string    nodeType("");
-    string    class("");
-    string    category("");
-    bool      hidden(false);
-    string    tooltip("");
+    string    Name("");
+    string    NodeType("");
+    string    Class("");
+    string    Category("");
+    bool      Hidden(false);
+    string    Tooltip("");
 };
 
 
 ESPstruct NodeType
 {
-    string    nodeId;
-    int       numChildren(0);
-    ESPstruct NodeInfoType nodeInfo;
+    string    NodeId;
+    int       NumChildren(0);
+    ESPstruct NodeInfoType NodeInfo;
 };
 
 
 ESPstruct ChoiceLimitType
 {
-    string    displayName;
-    string    itemType;
+    string    DisplayName;
+    string    ItemType;
 };
 
 
 ESPstruct InsertItemType
 {
-    string    name("");
-    string    nodeType("");
-    string    class("");
-    string    category("");
-    bool      required(false);
-    string    tooltip("");
-    ESParray<ESPstruct ChoiceLimitType, Choice> choiceList;
-    bool      fixedChoices(false);
+    string    Name("");
+    string    NodeType("");
+    string    Class("");
+    string    Category("");
+    bool      Required(false);
+    string    Tooltip("");
+    ESParray<ESPstruct ChoiceLimitType, ChoiceLimit> ChoiceList;
+    bool      FixedChoices(false);
 };
 
 
 ESPstruct AttributeType
 {
-    string     displayName;
-    string     name;
+    string     DisplayName;
+    string     Name;
+    string     Group("");
     string     tooltip("");
-    ESPstruct  TypeInfo type;
-    string currentValue("");
-    string defaultValue("");
-    bool   required(true);
-    bool   readOnly(false);
-    bool   hidden(false);
+    ESPstruct  TypeInfo Type;
+    string     CurrentValue("");
+    string     DefaultValue("");
+    string     CodeDefault("");
+    bool       Required(true);
+    bool       ReadOnly(false);
+    bool       Hidden(false);
+    bool       Deprecated(false);
 };
 
 
 ESPstruct AttributeValueType
 {
-    string    name;
-    string    value;
+    string    Name;
+    string    Value;
 };
 
 
 ESPresponse [exceptions_inline] GetNodeResponse : StatusResponse
 {
-    string nodeId;
-    ESPstruct NodeInfoType nodeInfo;
-    ESParray<ESPstruct AttributeType, Attribute> attributes;
-    ESParray<ESPstruct NodeType, Child> children;
-    ESParray<ESPstruct InsertItemType, Item> insertable;         // list of insertable elements under this node
-    bool localValueDefined(false);                               // true if the node is configured to have a value (not usually true)
-    ESPstruct AttributeType value;                               // this would be <element>value</element> not normal, see valueDefined
+    string NodeId;
+    ESPstruct NodeInfoType NodeInfo;
+    ESParray<ESPstruct AttributeType, Attribute> Attributes;
+    ESParray<ESPstruct NodeType, Child> Children;
+    ESParray<ESPstruct InsertItemType, Item> Insertable;         // list of insertable elements under this node
+    bool LocalValueDefined(false);                               // true if the node is configured to have a value (not usually true)
+    ESPstruct AttributeType Value;                               // this would be <element>value</element> not normal, see valueDefined
 };
 
 
 ESPrequest InsertNodeRequest  // response is same as GetPathRequest
 {
-    string sessionId;
-    string sessionLockKey;
-    string parentNodeId;
-    string nodeType;  // name of new instance to create
+    string SessionId;
+    string SessionLockKey;
+    string ParentNodeId;
+    string NodeType;  // name of new instance to create
 };
 
 
 ESPrequest SetValuesRequest
 {
-    string sessionId;
-    string sessionLockKey;
-    string nodeId;
-    ESParray<ESPstruct AttributeValueType, Attribute> attributeValues;
-    bool allowInvalid(false);  // true to allow setting an invalid value
-    bool forceCreate(false);   // force creaation of new value if not defined
-    string localValue("");
+    string SessionId;
+    string SessionLockKey;
+    string NodeId;
+    ESParray<ESPstruct AttributeValueType, Attribute> AttributeValues;
+    bool AllowInvalid(false);  // true to allow setting an invalid value
+    bool ForceCreate(false);   // force creaation of new value if not defined
+    string LocalValue("");
 };
 
 
 ESPresponse [exceptions_inline] GetParentsResponse
 {
-    ESParray<string, parentId> parentIdList;
+    ESParray<string, parentId> ParentIdList;
 };
 
 
@@ -239,107 +253,107 @@ ESPresponse [exceptions_inline] GetParentsResponse
 
 ESPstruct EnvironmentFileType
 {
-    string    filename;
-    bool      isActive(false);  // True if this is the current active environment
+    string    Filename;
+    bool      IsActive(false);  // True if this is the current active environment
 };
 
 
 ESPrequest CommonSessionRequest
 {
-    string sessionId;
+    string SessionId;
 };
 
 
 ESPresponse [exceptions_inline] GetEnvironmentListResponse
 {
-    ESParray<ESPstruct EnvironmentFileType, EnvironmentFile> environmentFiles;
+    ESParray<ESPstruct EnvironmentFileType, EnvironmentFile> EnvironmentFiles;
 };
 
 
 ESPrequest OpenEnvironmentFileRequest
 {
-    string sessionId;
-    string filename;
+    string SessionId;
+    string Filename;
 };
 
 
 ESPresponse [exceptions_inline] OpenEnvironmentFileResponse
 {
-    string rootNodeId;
+    string RootNodeId;
 };
 
 
 ESPrequest CloseEnvironmentFileRequest
 {
-    string sessionId;
-    string sessionLockKey;                // required if existing environment is modified and discarding changes
-    bool   discardChanges(false);         // discard modifications
+    string SessionId;
+    string SessionLockKey;                // required if existing environment is modified and discarding changes
+    bool   DiscardChanges(false);         // discard modifications
 };
 
 
 ESPrequest SaveEnvironmentFileRequest
 {
-    string sessionId;
-    string sessionLockKey;          // required if saving existing environment and it has been modified
-    string filename("");            // empty string means to overwrite the existing file
+    string SessionId;
+    string SessionLockKey;          // required if saving existing environment and it has been modified
+    string Filename("");            // empty string means to overwrite the existing file
 };
 
 
 ESPresponse [exceptions_inline] LockSessionResponse
 {
-    string sessionLockKey;       // filled in when a session is sucessfully locked
+    string SessionLockKey;       // filled in when a session is sucessfully locked
 };
 
 
 ESPrequest UnlockSessionRequest
 {
-    string sessionId;
-    string sessionLockKey;
+    string SessionId;
+    string SessionLockKey;
 };
 
 
 ESPrequest ValidateEnvironmentRequest
 {
-    string sessionId;
-    bool   includeHiddenNodes(false);   // includes hidden nodes (hidden attributes always included)
+    string SessionId;
+    bool   IncludeHiddenNodes(false);   // includes hidden nodes (hidden attributes always included)
 };
 
 
 ESPrequest GetTreeRequest
 {
-    string sessionId;
-    string nodeId;
-    bool   includeAttributes;
-    int    numLevels(1);
+    string SessionId;
+    string NodeId;
+    bool   IncludeAttributes;
+    int    NumLevels(1);
 };
 
 
 ESPstruct TreeElementType
 {
-    string    nodeId;
-    ESPstruct NodeInfoType nodeInfo;
-    ESParray<ESPstruct AttributeType, attribute> attributes;
-    ESParray<ESPstruct TreeElementType, Node> children;
+    string    NodeId;
+    ESPstruct NodeInfoType NodeInfo;
+    ESParray<ESPstruct AttributeType, attribute> Attributes;
+    ESParray<ESPstruct TreeElementType, Node> Children;
 };
 
 
 ESPresponse [exceptions_inline] GetTreeResponse
 {
-    ESPstruct TreeElementType tree;
+    ESPstruct TreeElementType Tree;
 };
 
 
 ESPrequest FetchNodesRequest
 {
-    string sessionId;
-    string startingNodeId("");   // optional starting node for the fetch, "" for none
-    string path;                 // path to search (uses XPath syntax). If startingNodeId specified, path may not start at root ("/")
+    string SessionId;
+    string StartingNodeId("");   // optional starting node for the fetch, "" for none
+    string Path;                 // path to search (uses XPath syntax). If startingNodeId specified, path may not start at root ("/")
 };
 
 
 ESPresponse [exceptions_inline] FetchNodesResponse
 {
-    ESParray<string, nodeId> nodeIds;
+    ESParray<string, nodeId> NodeIds;
 };
 
 

+ 34 - 6
esp/services/ws_config2/ws_config2Service.cpp

@@ -518,7 +518,10 @@ bool Cws_config2Ex::onFetchNodes(IEspContext &context, IEspFetchNodesRequest &re
     StringArray ids;
     for ( auto &&pNode : nodes)
     {
-        ids.append(pNode->getId().c_str());
+        if (!pNode->getSchemaItem()->isHidden())
+        {
+            ids.append(pNode->getId().c_str());
+        }
     }
     resp.setNodeIds(ids);
 
@@ -649,6 +652,7 @@ void Cws_config2Ex::getNodeResponse(const std::shared_ptr<EnvironmentNode> &pNod
     pNode->getInsertableItems(insertableList);
     for (auto it=insertableList.begin(); it!=insertableList.end(); ++it)
     {
+        bool addItem = true;
         std::shared_ptr<SchemaItem> pSchemaItem = (*it).m_pSchemaItem;
         Owned<IEspInsertItemType> pInsertInfo = createInsertItemType();
         pInsertInfo->setName(pSchemaItem->getProperty("displayName").c_str());
@@ -657,12 +661,11 @@ void Cws_config2Ex::getNodeResponse(const std::shared_ptr<EnvironmentNode> &pNod
         pInsertInfo->setCategory(pSchemaItem->getProperty("category").c_str());
         pInsertInfo->setRequired(pSchemaItem->isRequired());
         pInsertInfo->setTooltip(pSchemaItem->getProperty("tooltip").c_str());
-        std::string limitType = pSchemaItem->getProperty("insertLimitType");
-        if (!limitType.empty())
+        if (it->m_limitChoices)
         {
             pInsertInfo->setFixedChoices(true);
             IArrayOf<IEspChoiceLimitType> fixedChoices;
-            for (auto &&fc : (*it).m_itemLimits)
+            for (auto &fc : (*it).m_itemLimits)
             {
                 Owned<IEspChoiceLimitType> pChoice = createChoiceLimitType();
                 pChoice->setDisplayName(fc.itemName.c_str());
@@ -671,8 +674,13 @@ void Cws_config2Ex::getNodeResponse(const std::shared_ptr<EnvironmentNode> &pNod
                 fixedChoices.append(*pChoice.getLink());
             }
             pInsertInfo->setChoiceList(fixedChoices);
+            addItem = fixedChoices.ordinality() != 0;
+        }
+
+        if (addItem)
+        {
+            newNodes.append(*pInsertInfo.getLink());
         }
-        newNodes.append(*pInsertInfo.getLink());
     }
     resp.setInsertable(newNodes);
 
@@ -779,9 +787,11 @@ void Cws_config2Ex::getAttributes(const std::vector<std::shared_ptr<EnvironmentV
         pAttribute->setRequired(pSchemaValue->isRequired());
         pAttribute->setReadOnly(pSchemaValue->isReadOnly());
         pAttribute->setHidden(pSchemaValue->isHidden());
+        pAttribute->setDeprecated(pSchemaValue->isDeprecated());
+        pAttribute->setGroup(pSchemaValue->getGroup().c_str());
 
         std::vector<AllowedValue> allowedValues;
-        pSchemaValue->getAllowedValues(allowedValues, pAttr.get());
+        pSchemaValue->getAllowedValues(allowedValues, pAttr->getEnvironmentNode());
         if (!allowedValues.empty())
         {
             IArrayOf<IEspChoiceType> choices;
@@ -791,6 +801,24 @@ void Cws_config2Ex::getAttributes(const std::vector<std::shared_ptr<EnvironmentV
                 pChoice->setDisplayName((*valueIt).m_displayName.c_str());
                 pChoice->setValue((*valueIt).m_value.c_str());
                 pChoice->setDesc((*valueIt).m_description.c_str());
+                pChoice->setMsg((*valueIt).m_userMessage.c_str());
+                pChoice->setMsgType((*valueIt).m_userMessageType.c_str());
+
+                //
+                // Add dependencies
+                if ((*valueIt).hasDependencies())
+                {
+                    IArrayOf<IEspDependentValueType> dependencies;
+                    for (auto &depIt: (*valueIt).getDependencies())
+                    {
+                        Owned<IEspDependentValueType> pDep = createDependentValueType();
+                        pDep->setAttributeName(depIt.m_attribute.c_str());
+                        pDep->setAttributeValue(depIt.m_value.c_str());
+                        dependencies.append(*pDep.getLink());
+                    }
+                    pChoice->setDependencies(dependencies);
+                }
+
                 choices.append(*pChoice.getLink());
             }
             pAttribute->updateType().updateLimits().setChoiceList(choices);

+ 5 - 1
initfiles/componentfiles/config2xml/dali.xsd

@@ -16,6 +16,10 @@
 #    limitations under the License.
 ################################################################################
 -->
+
+
+Add a key for dali server names named dali_name that can be referred to from elsewhere that needs to select a dali.
+
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
 
     <xs:element name="DaliServerProcess">
@@ -423,4 +427,4 @@
             </xs:annotation>
         </xs:attribute>
     </xs:attributeGroup>
-</xs:schema>
+</xs:schema>

+ 32 - 40
initfiles/componentfiles/config2xml/eclagent.xsd

@@ -3,58 +3,50 @@
     xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"
     xmlns:hpcc="someuri">
     <xs:include schemaLocation="types.xsd"/>
-    <xs:complexType name="eclAgent" hpcc:class="component" hpcc:category="agentprocess" hpcc:componentName="eclagent" hpcc:displayName="ECL Agent Process">
-         <xs:attributeGroup name="Options" hpcc:displayName="Options" hpcc:tooltip="Options" hpcc:docid="EA.t2">
-            <xs:attribute name="allowedPipePrograms" type="xs:string" use="optional" default="*" hpcc:tab="Eclagent" hpcc:tooltip="Comma separated list of allowed PIPE programs (* for allow all)"/>
-            <xs:attribute name="daliServers" type="xs:string" use="required" hpcc:autogenforwizard="true" hpcc:tooltip="Specifies the dali server to which this eclagent is attached"/>
-            <xs:attribute name="defaultMemoryLimitMB" type="xs:nonNegativeInteger" use="optional" default="300" hpcc:tooltip="Default memory limit in MB for eclagent"/>
-            <xs:attribute name="heapUseHugePages" type="xs:boolean" default="false" hpcc:tooltip="Use memory from huge pages if they have been configured"/>
-            <xs:attribute name="heapUseTransparentHugePages" type="xs:boolean" default="true" hpcc:tooltip="Use memory from transparent huge pages"/>
-            <xs:attribute name="heapRetainMemory" type="xs:boolean" default="false" hpcc:tooltip="Retain and do not return unused memory to the operating system"/>
-            <xs:attribute name="pluginDirectory" type="absolutePath" use="optional" default="/opt/HPCCSystems/plugins/" hpcc:tooltip="Directory where plugins are located"/>
-            <xs:attribute name="traceLevel" type="xs:nonNegativeInteger" use="optional" default="0" hpcc:tooltip="Trace level"/>
-            <xs:attribute name="thorConnectTimeout" type="xs:nonNegativeInteger" use="optional" default="600" hpcc:tooltip="Default connection timeout when sending query to Thor"/>
-            <xs:attribute name="wuQueueName" type="xs:string" use="optional" default="" hpcc:tab="Eclagent" hpcc:tooltip="eclAgent Workunit Execution Queue Name" hpcc:autogenforwizard="true" hpcc:autogensuffix="_queue"/>
+    <xs:complexType name="eclAgent">
+        <xs:attributeGroup name="Options" hpcc:docid="EA.t2">
+            <xs:attribute name="allowedPipePrograms" hpcc:displayName="Allowed Pipe Programs" hpcc:group="Options" type="xs:string" use="optional" default="*" hpcc:tab="Eclagent" hpcc:tooltip="Comma separated list of allowed PIPE programs (* for allow all)"/>
+            <xs:attribute name="daliServers" hpcc:displayName="Dali Servers" hpcc:group="Options" type="xs:string" use="required" hpcc:tooltip="Specifies the dali server to which this eclagent is attached"/>
+            <xs:attribute name="defaultMemoryLimitMB" hpcc:displayName="Default Memory Limit (MB)" hpcc:group="Options" type="xs:nonNegativeInteger" use="optional" default="300" hpcc:tooltip="Default memory limit in MB for eclagent"/>
+            <xs:attribute name="heapUseHugePages" hpcc:displayName="Heap Use Huge Pages" hpcc:group="Options" type="xs:boolean" default="false" hpcc:tooltip="Use memory from huge pages if they have been configured"/>
+            <xs:attribute name="heapUseTransparentHugePages" hpcc:displayName="Heam Use Transparent Huge Pages" hpcc:group="Options" type="xs:boolean" default="true" hpcc:tooltip="Use memory from transparent huge pages"/>
+            <xs:attribute name="heapRetainMemory" hpcc:displayName="Heap Retain Memory" hpcc:group="Options" type="xs:boolean" default="false" hpcc:tooltip="Retain and do not return unused memory to the operating system"/>
+            <xs:attribute name="pluginDirectory" hpcc:displayName="Plugin Directory" hpcc:group="Options" type="absolutePath" use="optional" default="/opt/HPCCSystems/plugins/" hpcc:tooltip="Directory where plugins are located"/>
+            <xs:attribute name="traceLevel" hpcc:displayName="Trace Level" hpcc:group="Options" type="xs:nonNegativeInteger" use="optional" default="0" hpcc:tooltip="Trace level"/> < - Shoud this be an enumerated list, or a range say 0-10
+            <xs:attribute name="thorConnectTimeout" hpcc:displayName="Thor Connect Timeout" hpcc:group="Options" type="xs:nonNegativeInteger" use="optional" default="600" hpcc:tooltip="Default connection timeout when sending query to Thor"/>
+            <xs:attribute name="wuQueueName" hpcc:displayName="Workunit Queue Name" hpcc:group="Options" type="xs:string" use="optional" default="" hpcc:tooltip="eclAgent Workunit Execution Queue Name" hpcc:autogenforwizard="true" hpcc:autogensuffix="_queue"/> <!-- is this keyed? do we need new auto name option for suffix -->
         </xs:attributeGroup>
         <xs:sequence>
-            <xs:element name="EclAgentProcess" hpcc:docid="EA.t1">
+            <xs:element name="EclAgentProcess" hpcc:class="component" hpcc:componentName="eclagent" hpcc:displayName="ECL Agent Process" maxOccurs="unbounded" hpcc:docid="EA.t1">
                 <xs:complexType>
                     <xs:sequence>
                         <xs:element name="Instance" maxOccurs="unbounded" hpcc:displayName="Bound Computers">
                             <xs:complexType>
-                                <xs:attribute name="computer" type="xs:string" use="required"/>
-                                <xs:attribute name="netAddress" type="xs:string" use="optional" hpcc:readonly="true"/>
-                                <xs:attribute name="directory" type="xs:string" use="optional" default="c$\eclagent" hpcc:hidden="true"/>
+                                <xs:attributeGroup ref="computerNodeReference"/>
+                                <xs:attribute name="directory" type="xs:string" use="optional" default="c$\eclagent" hpcc:hidden="true"/> <!-- hidden doesn't make sense -->
                             </xs:complexType>
                         </xs:element>
-
-                        <xs:element name="Notes" minOccurs="0" maxOccurs="unbounded" hpcc:viewChildNodes="??true">
-                            <xs:complexType>
-                                <xs:sequence>
-                                    <xs:element name="Note" type="xs:string" minOccurs="0" maxOccurs="1"/>
-                                </xs:sequence>
-                                <xs:attribute name="severity" use="optional" default="Minor" hpcc:displayName="Severity" hpcc:tooltip="Significance of this note.">
-                                    <xs:simpleType>
-                                        <xs:restriction base="xs:string">
-                                            <xs:enumeration value="Minor"/>
-                                            <xs:enumeration value="Normal"/>
-                                            <xs:enumeration value="Critical"/>
-                                        </xs:restriction>
-                                    </xs:simpleType>
-                                </xs:attribute>
-                                <xs:attribute name="date" type="AutoTimeStampType" use="optional" hpcc:readOnly="true" hpcc:displayName="Date / Time" hpcc:tooltip="Date and time this note was entered"/>
-                                <xs:attribute name="computer" type="AutoComputerType" use="optional" hpcc:readOnly="true" hpcc:displayName="computer" hpcc:tooltip="Computer from which this note was entered"/>
-                                <xs:attribute name="user" type="AutoUseridType" use="optional" hpcc:readOnly="true" hpcc:displayName="User" hpcc:tooltip="User account from which this note was entered"/>
-                            </xs:complexType>
-                        </xs:element>
-
+                        <xs:element type="usernotes" hpcc:displayName="Notes"/>
                     </xs:sequence>
                     <xs:attributeGroup ref="buildInfo"/>
-                    <xs:attribute name="name" type="xs:string" use="required" hpcc:tooltip="Name for this process"/>
-                    <xs:attribute name="description" type="xs:string" use="optional" default="EclAgent process" hpcc:tooltip="Description for this process"/>
+                    <xs:attribute name="name" type="xs:string" use="required" hpcc:displayName="Name" hpcc:tooltip="Name for this process"/>
+                    <xs:attribute name="description" type="xs:string" use="optional" hpcc:displayName="Description" default="EclAgent process" hpcc:tooltip="Description for this process"/>
                     <xs:attributeGroup ref="Options"/>
                 </xs:complexType>
+
+                <xs:key name="eclagent_name_key">  <!-- does name need to be unique? -->
+                    <xs:selector xpath="." />
+                    <xs:field xpath="@name" />
+                </xs:key>
+                <xs:keyref name="eclagent_Instance_keyref" refer="computerNameKey">
+                    <xs:selector xpath="Instance"/>
+                    <xs:field xpath="@computer"/>
+                </xs:keyref>
+                <xs:keyref name="eclagent_Instance_ipref" refer="computerIPAddressKey">
+                    <xs:selector xpath="Instance"/>
+                    <xs:field xpath="netAddress"/>
+                </xs:keyref>
             </xs:element>
         </xs:sequence>
     </xs:complexType>
-</xs:schema>
+</xs:schema>

+ 26 - 26
initfiles/componentfiles/config2xml/environment.xsd

@@ -19,32 +19,32 @@
 <xs:schema
     xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"
     xmlns:hpcc="something hpcc.xsd">
-  <xs:include schemaLocation="types.xsd"/>
-  <xs:include schemaLocation="hardware.xsd"/>
-  <xs:include schemaLocation="esp.xsd"/>
-  <!--xs:include schemaLocation="esp_service_wsecl2.xsd"/-->
-  <xs:include schemaLocation="esp_service_smc.xsd"/>
-  <!--xs:include schemaLocation="dafilesrv.xsd"/-->
-  <!--xs:include schemaLocation="eclagent.xsd"/-->
-  <xs:element name="Environment" hpcc:category="root" hpcc:class="category">
-    <xs:complexType>
-      <xs:sequence>
-        <!--xs:element name="EnvSettings" hpcc:class="category" hpcc:displayName="System Settings" hpcc:hidden="true"></xs:element-->
-        <xs:element type="hardware" hpcc:class="category" hpcc:displayName="Hardware" hpcc:required="true"></xs:element>
-        <!--xs:element name="Programs" hpcc:class="category" hpcc:displayName="Programs" hpcc:hidden="true"></xs:element-->
-        <xs:element name="Software" hpcc:class="category" hpcc:displayName="Software">
-          <xs:complexType>
+    <xs:include schemaLocation="types.xsd"/>
+    <xs:include schemaLocation="hardware.xsd"/>
+    <xs:include schemaLocation="esp.xsd"/>
+    <!--xs:include schemaLocation="esp_service_wsecl2.xsd"/-->
+    <xs:include schemaLocation="esp_service_smc.xsd"/>
+    <!--xs:include schemaLocation="dafilesrv.xsd"/-->
+    <!--xs:include schemaLocation="eclagent.xsd"/-->
+    <xs:element name="Environment" hpcc:category="root" hpcc:class="category">
+        <xs:complexType>
             <xs:sequence>
-              <!--xs:element type="dafilesrv"/-->  <!-- this is like an include right now -->
-              <!--xs:element type="eclAgent"/-->
-              <!--xs:element type="ws_ecl"/-->
-              <xs:element type="espsmc"/>
-              <xs:element type="esp"/>
+                <!--xs:element name="EnvSettings" hpcc:class="category" hpcc:displayName="System Settings" hpcc:hidden="true"></xs:element-->
+                <xs:element type="hardware" hpcc:class="category" hpcc:displayName="Hardware" hpcc:required="true"></xs:element>
+                <!--xs:element name="Programs" hpcc:class="category" hpcc:displayName="Programs" hpcc:hidden="true"></xs:element-->
+                <xs:element name="Software" hpcc:class="category" hpcc:displayName="Software">
+                    <xs:complexType>
+                        <xs:sequence>
+                            <!--xs:element type="dafilesrv"/-->
+                            <!-- this is like an include right now -->
+                            <!--xs:element type="eclAgent"/-->
+                            <!--xs:element type="ws_ecl"/-->
+                            <xs:element type="espsmc"/>
+                            <xs:element type="esp"/>
+                        </xs:sequence>
+                    </xs:complexType>
+                </xs:element>
             </xs:sequence>
-          </xs:complexType>
-
-        </xs:element>
-      </xs:sequence>
-    </xs:complexType>
-  </xs:element>
+        </xs:complexType>
+    </xs:element>
 </xs:schema>

+ 3 - 2
initfiles/componentfiles/config2xml/esp.xsd

@@ -20,7 +20,7 @@
                                             <xs:attribute name="description" type="xs:string" use="optional" hpcc:displayName="Description"/>
                                             <xs:attribute name="path" type="xs:string" use="required" default="/" hpcc:displayName="Path" hpcc:tooltip="The logical path of a resource used for authentication"/>
                                             <xs:attribute name="resource" type="xs:string" use="required" hpcc:displayName="Resource" hpcc:tooltip="The physical resource for which access is checked"/>
-                                            <xs:attribute name="access" use="optional" default="Read">
+                                            <xs:attribute name="access" default="Read">
                                                 <xs:simpleType>
                                                     <xs:restriction base="xs:string">
                                                         <xs:enumeration value="" hpcc:description=""/>
@@ -71,7 +71,8 @@
                                     </xs:simpleType>
                                 </xs:attribute>
                                 <xs:attribute name="resourcesBasedn" type="xs:string" use="optional" hpcc:displayName="" hpcc:tooltip="Base location for resources (used with ldap security)"/>
-                                <xs:attribute name="service" type="xs:string" use="required" hpcc:hidden="true" hpcc:displayName="Service" />
+                                <xs:attribute name="service" type="xs:string" use="required" hpcc:codeDefault="123abc" hpcc:hidden="true" hpcc:displayName="Service"
+                                    hpcc:valueLimitRuleType="uniqueItemType_1" hpcc:valueLimitRuleData="EspBinding@service,/Environment/Software/EspService@name"/>
                                 <xs:attribute name="type" type="xs:string" use="optional" hpcc:displayName="Security Manager Plugin" hpcc:tooltip="The Security Manager to be used by the Esp Service"/>
                                 <xs:attribute name="workunitsBasedn" type="xs:string" use="optional" default="ou=workunits,ou=ecl" hpcc:displayName="WorkUnits BaseDn" hpcc:tooltip="Base location for workunit resources (used with ldap security)" hpcc:requiredIf="xpath,xpath..."/>
                                 <xs:attribute name="wsdlServiceAddress" type="xs:string" use="optional"hpcc:displayName="wsdlServiceAddress" hpcc:tooltip="Overrides the address used by client applications to connect to the service"/>

+ 32 - 14
initfiles/componentfiles/config2xml/esp_service_smc.xsd

@@ -6,11 +6,11 @@
     <xs:complexType name="espsmc">
 
         <xs:attributeGroup name="Monitoring" hpcc:docid="SMC-T02">
-            <xs:attribute name="monitorDaliFileServer" type="xs:boolean" use="true" default="false" hpcc:displayName="Monior Dali File Server" hpcc:tooltip="Warn if dafilesrv process is not running on computers"/>
-            <xs:attribute name="excludePartitions" type="xs:string" use="optional" default="/dev*,/sys,/proc/*" hpcc:displayName="Exclude Partitions" hpcc:tooltip="Comma, space or semicolon delimited list of partitions not to be monitored for free space"/>
-            <xs:attribute name="warnIfCpuLoadOver" type="xs:nonNegativeInteger" use="optional" default="95" hpcc:displayName="Warn CPU Load" hpcc:tooltip="CPU load over this value is flagged as warning in monitoring output"/>
-            <xs:attribute name="warnIfFreeStorageUnder" type="xs:nonNegativeInteger" use="optional" default="5" hpcc:displayName="Warn Free Storage" hpcc:tooltip="Available disk storage space under this value is flagged as warning in monitoring output"/>
-            <xs:attribute name="warnIfFreeMemoryUnder" type="xs:nonNegativeInteger" use="optional" default="5" hpcc:displayName="Warn Free Memory" hpcc:tooltip="Available memory under this value is flagged as warning in monitoring output"/>
+            <xs:attribute name="monitorDaliFileServer" type="xs:boolean" use="true" default="false" hpcc:displayName="Monior Dali File Server" hpcc:group="Monitoring" hpcc:tooltip="Warn if dafilesrv process is not running on computers"/>
+            <xs:attribute name="excludePartitions" type="xs:string" use="optional" default="/dev*,/sys,/proc/*" hpcc:displayName="Exclude Partitions" hpcc:group="Monitoring" hpcc:tooltip="Comma, space or semicolon delimited list of partitions not to be monitored for free space"/>
+            <xs:attribute name="warnIfCpuLoadOver" type="xs:nonNegativeInteger" use="optional" default="95" hpcc:displayName="Warn CPU Load" hpcc:group="Monitoring" hpcc:tooltip="CPU load over this value is flagged as warning in monitoring output"/>
+            <xs:attribute name="warnIfFreeStorageUnder" type="xs:nonNegativeInteger" use="optional" default="5" hpcc:displayName="Warn Free Storage" hpcc:group="Monitoring" hpcc:tooltip="Available disk storage space under this value is flagged as warning in monitoring output"/>
+            <xs:attribute name="warnIfFreeMemoryUnder" type="xs:nonNegativeInteger" use="optional" default="5" hpcc:displayName="Warn Free Memory" hpcc:group="Monitoring" hpcc:tooltip="Available memory under this value is flagged as warning in monitoring output"/>
         </xs:attributeGroup>
 
         <xs:sequence>
@@ -34,12 +34,12 @@
                                 <eventType>create</eventType>
                                 <eventAction>insertXML</eventAction>
                                 <eventData>
-                                <itemType>espbinding</itemType>
-                                <match>
-                                    <matchItemAttribute>service</matchItemAttribute>
-                                    <matchPath>/Environment/Software/EspService</matchPath>
-                                    <matchLocalAttribute>name</matchLocalAttribute>
-                                </match>
+                                    <itemType>espbinding</itemType>
+                                    <match>
+                                        <eventNodeAttribute>service</eventNodeAttribute>
+                                        <targetPath>/Environment/Software/EspService</targetPath>
+                                        <targetAttribute>name</targetAttribute>
+                                    </match>
                                     <xml>
                                         <Authenticate access="Read" description="Root access to SMC service" path="/" required="Read" resource="SmcAccess"/>
                                         <AuthenticateFeature description="Access to SMC service" path="SmcAccess" resource="SmcAccess" service="ws_smc"/>
@@ -91,15 +91,33 @@
                                         </ProcessFilters>
                                     </xml>
                                 </eventData>
-                            </xs:appinfo>
-
-                            <xs:appinfo hpcc:infoType="event">
+                            </xs:apinfo>
+                            <xs:appnfo hpcc:infoType="event">
                                 <eventType>create</eventType>
                                 <eventAction>addAttributeDependencies</eventAction>
                                 <eventData>
                                     <itemType>espbinding</itemType>
                                     <attribute attributeName="protocol" attributeValue="http" dependentAttribute="port" dependentValue="8010"/>
                                     <attribute attributeName="protocol" attributeValue="https" dependentAttribute="port" dependentValue="18010"/>
+                                    <match>
+                                        <eventNodeAttribute>service</eventNodeAttribute>
+                                        <targetPath>/Environment/Software/EspService</targetPath>
+                                        <targetAttribute>name</targetAttribute>
+                                    </match>
+                                </eventData>
+                            </xs:appinfo>
+
+                            <xs:appinfo hpcc:infoType="event">
+                                <eventType>create</eventType>
+                                <eventAction>setAttributeValue</eventAction>
+                                    <eventData>
+                                    <itemType>espbinding</itemType>
+                                    <attribute attributeName="resourcesBasedn" attributeValue="ou=SMC,ou=EspServices,ou=ecl"/>
+                                    <match>
+                                        <eventNodeAttribute>service</eventNodeAttribute>
+                                        <targetPath>/Environment/Software/EspService</targetPath>
+                                        <targetAttribute>name</targetAttribute>
+                                    </match>
                                 </eventData>
                             </xs:appinfo>
                         </xs:annotation>

+ 5 - 6
initfiles/componentfiles/config2xml/esp_service_wsecl2.xsd

@@ -3,17 +3,16 @@
     xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"
     xmlns:hpcc="someuri">
     <xs:include schemaLocation="types.xsd"/>
-    <xs:complexType name="ws_ecl" hpcc:class="component" hpcc:category="espservice" hpcc:componentName="ws_ecl" hpcc:displayName="WS ECL??" hpcc:namePrefix="myeclWatch">
+    <xs:complexType name="ws_ecl">
         <xs:sequence>
-            <xs:element name="EspService" maxOccurs="unbounded" hpcc:docid="MyWS2-T03">
+            <xs:element name="EspService" maxOccurs="unbounded" hpcc:class="component" hpcc:category="ESP Service" hpcc:displayName="WS ECL??" hpcc:componentName="ws_ecl" hpcc:docid="MyWS2-T03">
                 <xs:complexType>
                     <xs:sequence>
 
                         <xs:element name="ProcessCluster" minOccurs="0" maxOccurs="unbounded" hpcc:displayName="VIPS" hpcc:class="valueSet" hpcc:docid="MyWS2-T01">
                             <xs:complexType>
                                 <xs:attribute name="name" type="xs:string" use="required" hpcc:hidden="true" hpcc:autoGenerateType="prefix" hpcc:autoGenerateValue="proc"/>
-                                <xs:attribute name="roxie" type="xs:string" use="required" hpcc:displayName="Roxie" hpcc:tooltip=""
-                                              hpcc:category="select" hpcc:keyref="keyref to roxie names"/> <!-- type=xpathType /Environment/Software/RoxieCluster[@name!=$./*ProcessCluster/@roxie] -->
+                                <xs:attribute name="roxie" type="xs:string" use="required" hpcc:displayName="Roxie" hpcc:tooltip=""/>
                                 <xs:attribute name="vip" type="xs:string" use="required" hpcc:displayName="VIP" hpcc:tooltip=""/>
                                 <xs:attribute name="dnsInterval" type="xs:integer" use="optional" hpcc:displayName="DNS Cache timeout interval"
                                               hpcc:tooltip="DNS lookup cache timeout in seconds. Set to 0 to resolve DNS for every transaction.  Set to -1 (default) to keep DNS lookup cached indefinitely."/>
@@ -24,8 +23,8 @@
 
                         <xs:element name="Target" minOccurs="0" maxOccurs="unbounded" hpcc:displayName="Restrict To Target(s)" hpcc:docid="MyWS2-T02">
                             <xs:complexType>
-                                <xs:attribute name="name" type="xs:string" use="required" hpcc:category="select" hpcc:keyref="keyref to thor names (hthor, thor, roxie, see configmgr)"
-                                              hpcc:tooltip="WsEcl will only display specified targets, if none specified WsEcl will display all targets."/> <!-- type="topologyClusterType" -->
+                                <xs:attribute name="name" type="xs:string" use="required" hpcc:keyref="keyref to thor names (hthor, thor, roxie, see configmgr)"
+                                    hpcc:tooltip="WsEcl will only display specified targets, if none specified WsEcl will display all targets."/> <!-- type="topologyClusterType" -->
                             </xs:complexType>
                         </xs:element>
                     </xs:sequence>

+ 79 - 0
initfiles/componentfiles/config2xml/ldapserver.xsd

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+################################################################################
+#    HPCC SYSTEMS software Copyright (C) 2018 HPCC Systems®.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+################################################################################
+-->
+<xs:schema
+    xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"
+    xmlns:hpcc="someuri">
+    <xs:include schemaLocation="types.xsd"/>
+    <xs:complexType name="ldapserver">
+        <xs:sequence>
+            <xs:element name="LDAPServerProcess" hpcc:class="component" hpcc:category="LDAP Process" hpcc:componentName="ldapserver" hpcc:displayName="Active Directory LDAP process" hpcc:docid="ldapSrv" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element type="hwinstance" hpcc:displayName="Instances"/>
+                        <xs:element type="usernotes" hpcc:displayName="Notes"/>
+                    </xs:sequence>
+                    <xs:attributeGroup ref="buildInfo"/>
+                    <xs:attribute name="name" type="xs:string" use="required" hpcc:displayName="Name" hpcc:autoGenerateType="prefix" hpcc:autoGenerateValue="LDAP" hpcc:tooltip="Name for this process" />
+                    <xs:attribute name="description" type="xs:string" hpcc:displayName="Description" use="optional" default="LDAP server process" hpcc:tooptip="Description for this process"/> <!-- cant have default and optional -->
+                    <xs:attribute name="ldapPort" type="xs:nonNegativeInteger" hpcc:displayName="LDAP Port" use="required" default="389" hpcc:tooltip="The port of the ldap (Active Directory) server"/> <!-- key required ? -->
+                    <xs:attribute name="ldapSecurePort" type="xs:nonNegativeInteger" hpcc:displayName="LDAP Secure Port" use="required" default="636" hpcc:tooltip="The port of the ldap (Active Directory) server"/> <!-- key ? -->
+                    <xs:attribute name="ldapTimeoutSecs" type="xs:nonNegativeInteger" hpcc:displayName="Timeout (secs)" use="required" default="60" hpcc:tooltip="The maximum number of seconds to wait for most LDAP calls"/>  <!-- range? -->
+                    <xs:attribute name="cacheTimeout" type="xs:nonNegativeInteger" hpcc:displayName="Cache Timeout (minutes)" use="optional" default="5" hpcc:tooltip="Time in minutes after which the cached security information should expire"/>
+                    <xs:attribute name="sharedCache" type="xs:boolean" hpcc:displayName="Shared Cache" use="optional" default="true" hpcc:tooltip="Use a single, shared LDAP cache"/>
+                    <xs:attribute name="systemUser" type="xs:string" hpcc:displayName="System User" use="optional" hpcc:tooltip="An LDAP administrator account id to be used by HPCC to create and manage HPCC-specific LDAP branches"/>
+                    <xs:attribute name="systemPassword" type="xs:string" hpcc:displayName="System User Password" use="optional" hpcc:modifers="mask,verify" hpcc:tooltip="The password for the systemUser"/>
+                    <xs:attribute name="systemCommonName" type="xs:string" hpcc:displayName="System Common Name" use="optional" hpcc:requiredIf=".@systemUser" hpcc:tooltip="Required if systemUser is specified. The LDAP Common Name (cn) for the systemUser account as specified on the LDAP server"/>
+                    <xs:attribute name="systemBasedn" type="xs:string" hpcc:displayName="System Base DN" use="required" default="cn=Users" hpcc:tooltip="The ldap 'base distinguished name' of the systemUser"/>
+                    <xs:attribute name="groupsBasedn" type="xs:string" hpcc:displayName="Groups Base DN" use="required" default="ou=groups,ou=ecl" hpcc:tooltip="The ldap 'base distinguished name' that ecl server should use when looking up groups in the ldap (Active Directory) server"/>
+                    <xs:attribute name="viewsBasedn" type="xs:string" hpcc:displayName="Views Base DN" use="required" default="ou=views,ou=ecl" hpcc:tooltip="The ldap 'base distinguished name' that ecl server should use when looking up views in the ldap (Active Directory) server"/>
+                    <xs:attribute name="usersBasedn" type="xs:string" hpcc:displayName="Users Base DN" use="required" default="ou=users,ou=ecl" hpcc:tooltip="The ldap 'base distinguished name' that ecl server should use when looking up users in the ldap (Active Directory) server"/>
+                    <xs:attribute name="modulesBasedn" type="xs:string" hpcc:displayName="Modules Base DN" use="required" default="ou=modules,ou=ecl" hpcc:tooltip="The ldap 'base distinguished name' that ecl server should use when looking up modules in the ldap (Active Directory) server"/>
+                    <xs:attribute name="workunitsBasedn" type="xs:string" hpcc:displayName="Workunits Base DN" use="required" default="ou=workunits,ou=ecl" hpcc:tooltip="The ldap 'base distinguished name' that ecl server should use when looking up workunit scopes in the ldap (Active Directory) server"/>
+                    <xs:attribute name="filesBasedn" type="xs:string" hpcc:displayName="Files Base DN" use="required" default="ou=files,ou=ecl" hpcc:tooltip="The ldap 'base distinguished name' that ecl server should use when looking up file scopes in the ldap (Active Directory) server"/>
+                    <xs:attribute name="sudoersBasedn" type="xs:string" hpcc:displayName="Sudoers Base DN" use="optional" default="ou=SUDOers" hpcc:tooltip="The place to hold the sudoers entries"/>
+                    <xs:attribute name="serverType" use="required" hpcc:displayName="Server Type" default="ActiveDirectory" hpcc:tooltip="LDAP Server Implementation Type">
+                        <xs:simpleType>
+                            <xs:restriction base="xs:string">
+                                <xs:enumeration value="ActiveDirectory" hpcc:displayName="" hpcc:description=""/>
+                                <xs:enumeration value="OpenLDAP" hpcc:description=""/>
+                                <xs:enumeration value="389DirectoryServer" hpcc:description=""/>
+                                <xs:enumeration value="Fedora389" hpcc:description=""/>
+                            </xs:restriction>
+                        </xs:simpleType>
+                    </xs:attribute>
+                </xs:complexType>
+
+                <xs:key name="ldap_name_key">
+                    <xs:selector xpath="." />
+                    <xs:field xpath="@name" />
+                </xs:key>
+
+                <xs:keyref name="espprocess_Instance_keyref" refer="computerNameKey">
+                    <xs:selector xpath="Instance"/>
+                    <xs:field xpath="@computer"/>
+                </xs:keyref>
+
+                <xs:keyref name="espprocess_Instance_ipref" refer="computerIPAddressKey">
+                    <xs:selector xpath="Instance"/>
+                    <xs:field xpath="netAddress"/>
+                </xs:keyref>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+</xs:schema>

+ 346 - 0
initfiles/componentfiles/config2xml/roxie.xsd

@@ -0,0 +1,346 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+################################################################################
+#    HPCC SYSTEMS software Copyright (C) 2018 HPCC Systems®.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+################################################################################
+-->
+<xs:schema
+    xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"
+    xmlns:hpcc="someuri">
+    <xs:include schemaLocation="types.xsd"/>
+    <xs:complexType name="roxiecluster">
+        <xs:sequence>
+            <xs:element name="RoxieCluster" maxOccurs="unbounded" hpcc:displayName="Roxie Cluster" hpcc:class="component" hpcc:componentName="roxiecluster">
+                <!-- should make this default to the complexType name -->
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="RoxieFarmProcess" hpcc:displayName="Ports" maxOccurs="unbounded">
+                            <xs:complexType>
+                                <xs:sequence>
+                                    <xs:element name="RoxieServerProcess" hpcc:hidden="true"/>
+                                </xs:sequence>
+                                <xs:attribute name="port" hpcc:displayName="Port" type="xs:nonNegativeInteger" use="required" default="9876" hpcc:tooltip="the network port on which the Roxie servers accept connections"/>
+                                <xs:attribute name="numThreads" hpcc:displayName="Number of Threads" type="xs:nonNegativeInteger" use="optional" default="30" hpcc:tooltip="Number of simultaneous queries Roxie servers will accept on this port"/>
+                                <xs:attribute name="listenQueue" hpcc:displayName="Listen Queue Connections" type="xs:nonNegativeInteger" use="optional" default="200" hpcc:tooltip="Number of pending connections that can be accepted"/>
+                                <xs:attribute name="requestArrayThreads" hpcc:displayName="Request Array Threads" type="xs:nonNegativeInteger" use="optional" default="5" hpcc:tooltip="Number of simultaneous queries Roxie servers will process using the MERGE option of SOAPCALL"/>
+                                <xs:attribute name="aclName" hpcc:displayName="ACL" type="xpathType" use="optional" hpcc:tooltip="Name of any Access Control List to use"/> <!-- keyref to ACL list -->
+                                <xs:attribute name="protocol" hpcc:displayName="Protocol" type="xs:string" use="required" default="native" hpcc:tooltip="Protocol to use">
+                                    <xs:simpleType>
+                                        <xs:restriction base="xs:string">
+                                            <xs:enumeration value="native" hpcc:description=""/>
+                                            <xs:enumeration value="ssl" hpcc:description=""/>
+                                        </xs:restriction>
+                                    </xs:simpleType>
+                                </xs:attribute>
+                                <xs:attribute name="passphrase" hpcc:displayName="Pass Phrase" hpcc:modifiers="mask,verify" type="xs:string" use="optional" hpcc:tooltip="Pass phrase for cert"/>
+                                <xs:attribute name="certificateFileName" hpcc:displayName="Certificate Filename" type="xs:string" use="optional" hpcc:tooltip="Path to certificate filename"/>
+                                <xs:attribute name="privateKeyFileName" hpcc:displayName="Private Key Filename" type="xs:string" use="optional" hpcc:displayName="Path to private key filename"/> <!-- perhaps a type for filepath that verifies well formed path -->
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element name="RoxieServerProcess" hpcc:displayName="Servers" maxOccurs="unbounded"> <!--special view type needed to collect together all of these somehow -->
+                            <xs:complexType>
+                                <xs:attribute name="name" type="nodeName" use="required" hpcc:readOnly="true" hpcc:mirrorFrom="/Environment/Hardware/Computer@name"/>
+                                <xs:attributeGroup ref="computerNodeReference"/>
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element name="ACL" hpcc:displayName="Access Control Lists" maxOccurs="unbounded">
+                            <!-- need same kind of thing like RoxieServerProcess -->
+                            <xs:complexType>
+                                <xs:sequence>
+                                    <xs:element name="BaseList" minOccurs="0" maxOccurs="unbounded" hpcc:tooltip="Base Access Control Lists (Ordered List)">
+                                        <xs:complexType>
+                                            <xs:attribute name="name" type="xs:string" hpcc:displayName="Name" use="required" hpcc:tooltip="Name of another Access Control List to extend"/>
+                                        </xs:complexType>
+                                    </xs:element>
+                                    <xs:element name="Access" minOccurs="0" maxOccurs="unbounded" hpcc:tooltip="Access Rules (Ordered List)">
+                                        <xs:complexType>
+                                            <xs:attribute name="allow" type="yesno" hpcc:displayName="Allow" use="required" default="yes"/>
+                                            <xs:attribute name="ip" type="ipV4Address" hpcc:displayName="IP Address" use="optional" default="0.0.0.0" hpcc:tooltip="IP Address of target system"/>
+                                            <xs:attribute name="mask" type="ipV4Address" hpcc:displayName="Internet Mask" use="optional" default="255.255.255.255" hpcc:tooltip="Internet address mask"/>
+                                            <xs:attribute name="query" type="xs:string" hpcc:displayName="Query Wildcard" use="optional" hpcc:codeDefault=".*" hpcc:tooltip="wildcard for queries to allow/disallow"/>
+                                            <xs:attribute name="errorCode" type="xs:nonNegativeInteger" hpcc:displayName="Error Code" use="optional" hpcc:tooltip="optional error code to associate with the query"/>
+                                            <xs:attribute name="error" type="xs:string" hpcc:displayName="Error Message" use="optional" hpcc:tooltip="optional error message to associate with the query"/>
+                                            <xs:attribute name="name" type="xs:string" hpcc:displayName="Name" use="required" hpcc:autoGenerateType="prefix_" hpcc:autoGenerateValue="ACLrule" hpcc:tooltip="Name of this Access Control Rule"/>
+                                        </xs:complexType>
+                                    </xs:element>
+                                </xs:sequence>
+                                <xs:attribute name="name" type="xs:string" hpcc:displayName="Name" use="required" hpcc:autoGenerateType="prefix_" hpcc:autoGenerateValue="ACL"/>
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element name="PreferredCluster" mpcc:displayName="Preferred Clusters" maxOccurs="unbounded">
+                            <xs:complexType>
+                                <xs:attribute name="name" type="xs:string" use="required" hpcc:autoGenerateType="prefix_" hpcc:autoGenerateValue="PreferredCluster" hpcc:tooltip="Name of the cluster"/>
+                                <xs:attribute name="priority" type="xs:integer" use="required" hpcc:tooltip="Priority (negative to disable)"/>
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element name="UserMetric" mpcc:displayName="User Metrics" maxOccurs="unbounded">
+                            <xs:complexType>
+                                <xs:attribute name="name" type="xs:string" use="required" hpcc:autoGenerateType="prefix_" hpcc:autoGenerateValue="UserMetric" hpcc:tooltip="Name of this metric"/>
+                                <xs:attribute name="regex" type="xs:integer" use="required" hpcc:tooltip="Expression to match"/>
+                            </xs:complexType>
+                        </xs:element>
+                        <xs:element type="usernotes" hpcc:displayName="Notes"/>
+                    </xs:sequence>
+                    <!-- General RoxieCluster Attributes -->
+                    <xs:attributeGroup ref="buildInfo"/>
+                    <xs:attribute name="name" type="xs:string" hpcc:displayName="Name" use="required" hpcc:autoGenerateType="prefix_" hpcc:autoGenerateValue="roxie" hpcc:tooltip="Name for this process"/>
+                    <xs:attribute name="description" type="xs:string" hpcc:displayName="Description" use="optional" default="Roxie cluster" hpcc:tooltip="Description for this process"/>
+                    <xs:attribute name="daliServers" type="xs:string" hpcc:displayName="Dali Server" use="optional" hpcc:tooltip="Specifies the dali server to which this roxie is attached"/>
+                    <xs:attribute name="lockDali" type="xs:boolean" hpcc:displayName="Lock Dali" use="optional" default="false" hpcc:tooltip="If set, Roxie will use cached info from dali only, and will not connect to dali or refresh the cache"/>
+                    <!-- hpcc:codeDefault instead? -->
+                    <xs:attribute name="multicastBase" type="ipV4Address" hpcc:displayName="Multicast Base IP Address" use="optional" default="239.1.1.1" hpcc:tooltip="The base multicast IP for this roxie cluster. Multicast ranges must not overlap for any roxie clusters in the same multicast domain"/>
+                    <!-- hpcc:codeDefault instead? current default looks pretty specific -->
+                    <xs:attribute name="multicastLast" type="ipV4Address" hpcc:displayName="Multicast Last IP Address" use="optional" default="239.1.254.254" hpcc:tooltip="The last multicast IP available for this roxie cluster. Multicast ranges must not overlap for any roxie clusters in the same multicast domain"/>
+                    <!-- hpcc:codeDefault instead? current default looks pretty specific, should this be required if multicastBase is set? -->
+                    <xs:attribute name="multicastTTL" type="xs:nonNegativeInteger" hpcc:displayName="Multicat Time To Live" use="optional" default="1" hpcc:tooltip="The multicast TTL (Time To Live) setting for this roxie cluster.  Zero means do not explicitly set TTL, and use the default OS setting"/>
+                    <xs:attribute name="directory" type="absolutePath" hpcc:displayName="Directory" use="optional" default="${EXEC_PREFIX}/lib/${DIR_NAME}/roxie/" hpcc:tooltip="Specifies the directory to which the software will be deployed"/>
+                    <!-- @XSD_PLUGIN_DEFINITION@ LN injects an attribute!! -->
+                    <xs:attribute name="pluginsPath" type="relativePath" hpcc:displayName="Plugins Path" use="optional" default="${PLUGINS_PATH}" hpcc:tooltip="Alternate path where plugin files are deployed (./plugins is assumed if not specified)"/>
+                    <!-- LDAP attributes -->
+                    <xs:attribute name="ldapUser" type="xs:string" hpcc:displayName="LDAP User" hpcc:group="LDAP" use="optional" default="roxie" hpcc:tooltip="Specifies the user name for LDAP file access checking"/>
+                    <xs:attribute name="ldapPassword" type="xs:string" hpcc:displayName="LDAP User Password" hpcc:group="LDAP" use="optional" hpcc:modifiers="mask,verify" hpcc:tooltip="Specifies the user name for LDAP file access checking"/>
+                    <!-- Options attributes -->
+                    <xs:attribute name="affinity" type="xs:nonNegativeInteger" hpcc:displayName="Affinity" hpcc:group="Options" use="optional" default="0" hpcc:tooltip="If non-zero, binds the roxie process to use the specified cores only (bitmask)"/>
+                    <xs:attribute name="allFilesDynamic" type="xs:boolean" hpcc:displayName="All Files Dynamic" hpcc:group="Options" use="optional" default="false" hpcc:tooltip="If enabled, files will be resolved per-query and not locked between queries"/>
+                    <xs:attribute name="backgroundCopyClass" hpcc:displayName="Background Copy Class" hpcc:group="Options" default="none" hpcc:tooltip="Specify an IONICE class for the background copy thread">
+                        <xs:simpleType>
+                            <xs:restriction base="xs:string">
+                                <xs:enumeration value="none" hpcc:displayName="None" hpcc:description=""/>
+                                <xs:enumeration value="best-effort" hpcc:displayName="Best Effort" hpcc:description=""/>
+                                <xs:enumeration value="idle" hpcc:displayName="Idle" hpcc:description=""/>
+                            </xs:restriction>
+                        </xs:simpleType>
+                    </xs:attribute>
+                    <xs:attribute name="backgroundCopyPrio" hpcc:displayName="Background Copy Priority" hpcc:group="Options" use="optional" default="0" hpcc:tooltip="Specify an IONICE value for the background copy thread, if backgroundCopyClass set to best-effort">
+                        <!-- Is this value required if the backgroundcopyclass is set to a particular value -->
+                        <xs:simpleType>
+                            <!-- This is how to do a range, If not desired, add type="xs:nonNegativeInteger" above and remove the simpleType section -->
+                            <xs:restriction base="xs:nonNegativeInteger">
+                                <xs:minInclusive value="1"/>
+                                <xs:maxInclusive value="100"/>
+                            </xs:restriction>
+                        </xs:simpleType>
+                    </xs:attribute>
+                    <xs:attribute name="callbackRetries" type="xs:nonNegativeInteger" hpcc:displayName="Callback Retries" hpcc:group="Options" use="optional" default="3" hpcc:tooltip="Number of retries before callbacks from agents to server are aborted"/>
+                    <xs:attribute name="callbackTimeout" type="xs:nonNegativeInteger" hpcc:displayName="Callback Timeout" hpcc:group="Options" use="optional" default="5000" hpcc:tooltip="Timeout (in ms) before callbacks from agents to server are resent"/>
+                    <!-- range? -->
+                    <xs:attribute name="checkFileDate" type="xs:boolean" hpcc:displayName="Check File Date" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Compare file dates of physical files with the information in DFS"/>
+                    <xs:attribute name="copyResources" type="xs:boolean" hpcc:displayName="Copy Resources" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Copies any missing data files/keys from the position they were in when query was deployed"/>
+                    <xs:attribute name="coresPerQuery" type="xs:nonNegativeInteger" hpcc:displayName="Cores Per Query" hpcc:group="options" use="optional" default="0" hpcc:tooltip="If non-zero, binds each incoming query to use the specified number of cores only"/>
+                    <xs:attribute name="debugPermitted" type="xs:boolean" hpcc:displayName="Debug Permitted" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Allow the ECL query debugger to attach to queries on this Roxie"/>
+                    <xs:attribute name="defaultHighPriorityTimeLimit" type="xs:nonNegativeInteger" hpcc:displayName="Default High Priority Time Limit (ms)" hpcc:group="Options" use="optional" default="0" hpcc:tooltip="Maximum run time (in ms) for any single active high-priority query (if not overriden)"/>
+                    <!-- range? -->
+                    <xs:attribute name="defaultHighPriorityTimeWarning" type="xs:nonNegativeInteger" hpcc:displayName="Default High Priority Time Warning (ms)" hpcc:group="Options" use="optional" default="5000" hpcc:tooltip="Time (in ms) before generating SNMP warning for a high-priority query (if not overriden)"/>
+                    <xs:attribute name="defaultLowPriorityTimeLimit" type="xs:nonNegativeInteger" hpcc:displayName="Default Low Priority Time Limit (ms)" hpcc:group="Options" use="optional" default="0" hpcc:tooltip="Maximum run time (in ms) for any single active low-priority query (if not overriden)"/>
+                    <xs:attribute name="defaultLowPriorityTimeWarning" type="xs:nonNegativeInteger" hpcc:displayName="Default Low Priority Time Warning (ms)" hpcc:group="Options" use="optional" default="0" hpcc:tooltip="Time (in ms) before generating SNMP warning for a low-priority query (if not overriden)"/>
+                    <xs:attribute name="defaultMemoryLimit" type="xs:nonNegativeInteger" hpcc:displayName="Default Memory Limit (bytes)" hpcc:group="Options" use="optional" default="0" hpcc:tooltip="Maximum amount of memory available for row data in any single active query (if not overriden)"/>
+                    <xs:attribute name="defaultSLAPriorityTimeLimit" type="xs:nonNegativeInteger" hpcc:displayName="Default SLA Priority Time Limit (ms)" hpcc:group="Options" use="optional" default="0" hpcc:tooltip="Maximum run time (in ms) for any single active SLA-high-priority query (if not overriden)"/>
+                    <xs:attribute name="defaultSLAPriorityTimeWarning" type="xs:nonNegativeInteger" hpcc:displayName="Default SLA Priority Time Warning (ms)" hpcc:group="Options" use="optional" default="5000" hpcc:tooltip="Time (in ms) before generating SNMP warning for a SLA-high-priority query (if not overriden)"/>
+                    <xs:attribute name="defaultStripLeadingWhitespace" type="xs:boolean" hpcc:displayName="Default Strip Leading Whitespace" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Default value for stripping leading whitespace in input XML values"/>
+                    <xs:attribute name="enableKeyDiff" type="xs:boolean" hpcc:displayName="Enable Key Diff" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Enable / Disable key diff functionality in roxie"/>
+                    <xs:attribute name="enableSysLog" type="xs:boolean" hpcc:displayName="Enable Sys Log" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Enable use of syslog for monitoring"/>
+                    <xs:attribute name="flushJHtreeCacheOnOOM" type="xs:boolean" hpcc:displayName="flushJHtreeCacheOnOOM" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Should the index node memory allocation flush the cache and retry if memory allocation fails"/>
+                    <xs:attribute name="fieldTranslationEnabled" use="optional" hpcc:displayName="Enable Field Translation" hpcc:group="Options" default="false" hpcc:tooltip="Enables translation (where possible) of mismatched index layouts on-the-fly. Specify 'payload' to attempt to translate payload fields only">
+                        <xs:simpleType>
+                            <xs:restriction base="xs:string">
+                                <xs:enumeration value="false" hpcc:displayName="False" hpcc:desciption=""/>
+                                <xs:enumeration value="true" hpcc:displayName="true" hpcc:description=""/>
+                                <xs:enumeration value="payload" hpcc:displayName="Payload" hpcc:description=""/>
+                            </xs:restriction>
+                        </xs:simpleType>
+                    </xs:attribute>
+                    <xs:attribute name="highTimeout" type="xs:nonNegativeInteger" hpcc:displayName="High Timeout (ms)" hpcc:group="Options" use="optional" default="2000" hpcc:tooltip="Timeout (in ms) before high priority requests are resent to agents"/>
+                    <!-- range, min value? -->
+                    <xs:attribute name="httpCallerIdHeader" type="xs:string" hpcc:displayName="http Caller ID Header" hpcc:group="Options" use="optional" default="HPCC-Caller-Id" hpcc:tooltip="HTTP Header field to use for sending and receiving CallerId"/>
+                    <xs:attribute name="httpGlobalIdHeader" type="xs:string" hpcc:displayName="http Global ID Header" hpcc:group="Options" use="optional" default="HPCC-Global-Id" hpcc:tooltip="HTTP Header field to use for sending and receiving GlobalId"/>
+                    <xs:attribute name="ignoreOrphans" type="xs:boolean" hpcc:displayName="Ignore Orphans" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Treat out-of-date local files as if they were not present"/>
+                    <xs:attribute name="lazyOpen" hpcc:displayName="Ignore Orphans" hpcc:group="Options" use="optional" default="smart" hpcc:tooltip="Delay opening files until first use. Select smart to use lazy mode only after a restart">
+                        <xs:simpleType>
+                            <xs:restriction base="xs:string">
+                                <xs:enumeration value="false" hpcc:displayName="False" hpcc:description=""/>
+                                <xs:enumeration value="true" hpcc:displayName="True" hpcc:description=""/>
+                                <xs:enumeration value="smart" hpcc:displayName="Smart" hpcc:description=""/>
+                            </xs:restriction>
+                        </xs:simpleType>
+                    </xs:attribute>
+                    <xs:attribute name="localFilesExpire" type="xs:integer" hpcc:displayName="Local Files Expire (ms)" hpcc:group="Options" use="optional" default="-1" hpcc:tooltip="Period (in ms) of inactivity before a local datafile handle is closed"/>
+                    <xs:attribute name="localSlave" type="xs:boolean" hpcc:displayName="Local Slave" hpcc:group="Options" use="optional" default="false" hpcc:tooltip="All Roxie servers talk only to their embedded agent"/>
+                    <xs:attribute name="lockSuperFiles" type="xs:boolean" hpcc:displayName="Lock SuperFiles" hpcc:group="Options" use="optional" default="false" hpcc:tooltip="If enabled, superfiles will be locked while queries that use them are loaded"/>
+                    <xs:attribute name="lowTimeout" type="xs:nonNegativeInteger" hpcc:displayName="Low Timeout (ms)" hpcc:group="Options" use="optional" default="10000" hpcc:tooltip="Timeout (in ms) before low priority requests are resent to agents"/>
+                    <xs:attribute name="maxLocalFilesOpen" type="xs:nonNegativeInteger" hpcc:displayName="Max Local Files Open" hpcc:group="Options" use="optional" default="4000" hpcc:tooltip="Maximum number of local files to keep open"/>
+                    <xs:attribute name="maxRemoteFilesOpen" type="xs:nonNegativeInteger" hpcc:displayName="Max Remote Files Open" hpcc:group="Options" use="optional" default="1000" hpcc:tooltip="Maximum number of remote files to keep open"/>
+                    <xs:attribute name="minFreeDiskSpace" type="xs:nonNegativeInteger" hpcc:displayName="Mininum Free Disk Space (bytes)" hpcc:group="Options" use="optional" default="1073741824" hpcc:tooltip="Minimum amount of disk space needed to be available for file copy to succeed"/>
+                    <xs:attribute name="minLocalFilesOpen" type="xs:nonNegativeInteger" hpcc:displayName="Minumum Local Files Open" hpcc:group="Options" use="optional" default="2000" hpcc:tooltip="Minimum number of local files to keep open"/>
+                    <xs:attribute name="minRemoteFilesOpen" type="xs:nonNegativeInteger" hpcc:displayName="Minimum Remote Files Open" hpcc:group="Options" use="optional" default="500" hpcc:tooltip="Minimum number of remote files to keep open"/>
+                    <xs:attribute name="monitorDaliFileServer" type="xs:boolean" hpcc:displayName="Monitor Dali File Server" hpcc:group="Options" use="optional" default="false" hpcc:tooltip="Warn if dafilesrv process is not running on computers"/>
+                    <xs:attribute name="preferredSubnet" type="ipV4Address" hpcc:displayName="Preferred Subnet" hpcc:group="Options" use="optional" default="" hpcc:tooltip="Preferred subnet to use for multi-NIC machines"/>
+                    <xs:attribute name="preferredSubnetMask" type="ipV4Address" hpcc:displayName="Preferred Subnet Mask" hpcc:group="Options" use="optional" default="" hpcc:tooltip="Preferred subnet mask to use for multi-NIC machines"/>
+                    <xs:attribute name="preloadOnceData" type="xs:boolean" hpcc:displayName="Preload Once Data" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Evaluate : ONCE sections of queries at query load time"/>
+                    <xs:attribute name="prestartSlaveThreads" type="xs:boolean" hpcc:displayName="Prestart Slave Threads" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Prestart slave worker threads at startup"/>
+                    <xs:attribute name="reloadRetriesFailed" type="xs:boolean" hpcc:displayName="Reload Retries Failed" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Retry loading of failed queries whenever QuerySet reloads"/>
+                    <xs:attribute name="remoteFilesExpire" type="xs:integer" hpcc:displayName="Remte Files Expire (ms)" hpcc:group="Options" use="optional" default="3600000" hpcc:tooltip="Period (in ms) of inactivity before a remote datafile handle is closed"/>
+                    <xs:attribute name="serverThreads" type="xs:nonNegativeInteger" hpcc:displayName="Server Threads" hpcc:group="Options" use="optional" default="30" hpcc:tooltip="Default number of threads processing Roxie server requests (if not specifed on Servers tab)"/>
+                    <xs:attribute name="siteCertificate" type="xpathType" hpcc:displayName="Site Certificate" hpcc:group="Options" use="optional" hpcc:tooltip="Name of the site certificate component that is used for security">
+                        <xs:annotation>
+                            <xs:appinfo>
+                                <tooltip></tooltip>
+                                <xpath>/Environment/Software/SiteCertificate</xpath>
+                            </xs:appinfo>
+                        </xs:annotation>
+                    </xs:attribute>
+                    <xs:attribute name="slaTimeout" type="xs:nonNegativeInteger" hpcc:displayName="SLA Timeout (ms)" hpcc:group="Options" use="optional" default="2000" hpcc:tooltip="Timeout (in ms) before SLA high priority requests are resent to agents"/>
+                    <xs:attribute name="slaveQueryReleaseDelaySeconds" type="xs:nonNegativeInteger" hpcc:displayName="Slave Query Release Delay (s)" hpcc:group="Options" use="optional" default="60" hpcc:tooltip="Delay before unregistering slave queries to allow in-flight to complete. Files are locked until query is unregistered"/>
+                    <xs:attribute name="slaveThreads" type="xs:nonNegativeInteger" hpcc:displayName="Slave Threads" hpcc:group="Options" use="optional" default="30" hpcc:tooltip="Number of threads processing agent requests"/>
+                    <xs:attribute name="statsExpiryTime" type="xs:nonNegativeInteger" hpcc:displayName="Stats Expire Time (s)" hpcc:group="Options" use="optional" default="3600" hpcc:tooltip="Time (in seconds) that detailed reporting stats are kept"/>
+                    <xs:attribute name="totalMemoryLimit" type="xs:nonNegativeInteger" hpcc:displayName="Total Memory Limit (bytes)" hpcc:group="Options" use="optional" default="1073741824" hpcc:tooltip="Maximum amount of memory available for row data in all active queries"/>
+                    <xs:attribute name="heapUseHugePages" type="xs:boolean" hpcc:displayName="Use Heap Huge Pages" hpcc:group="Options" default="false" hpcc:tooltip="Allow roxie to use memory from huge pages if they have been configured"/>
+                    <xs:attribute name="heapUseTransparentHugePages" type="xs:boolean" hpcc:displayName="Use Heap Transparent Huge Pages" hpcc:group="Options" default="true" hpcc:tooltip="Allow roxie to use memory from transparent huge pages"/>
+                    <xs:attribute name="heapRetainMemory" type="xs:boolean" hpcc:displayName="Retain Heap Memory" hpcc:group="Options" default="false" hpcc:tooltip="Retain and do not return unused memory to the operating system"/>
+                    <xs:attribute name="trapTooManyActiveQueries" type="xs:boolean" hpcc:displayName="Trap Too Many Active Queries" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="should an SNMP trap get sent when too many active query error occurs"/>
+                    <xs:attribute name="useHardLink" type="xs:boolean" hpcc:displayName="Use Hard Link" hpcc:group="Options" use="optional" default="false" hpcc:tooltip="If the data file exists on the current machine but in a different directory than roxie expects - create a hard link"/>
+                    <xs:attribute name="useMemoryMappedIndexes" type="xs:boolean" hpcc:displayName="Use Memory Mapped Indices" hpcc:group="Options" use="optional" default="false" hpcc:tooltip="Using memory-mapped files when merging multiple result streams from row-compressed indexes"/>
+                    <xs:attribute name="useRemoteResources" type="xs:boolean" hpcc:displayName="Use Remote Resources" hpcc:group="Options" use="optional" default="true" hpcc:tooltip="Reads any missing data files/keys from the position they were in when deployed"/>
+
+                    <!-- Redundancy attributes -->
+                    <xs:attribute name="cyclicOffset" type="xs:nonNegativeInteger" hpcc:displayName="Cyclic Offset" hpcc:group="Redundancy" use="optional" default="1" hpcc:tooltip="Offset for cyclic redundancy mode"/>
+                    <xs:attribute name="channelsPerNode" type="xs:nonNegativeInteger" hpcc:displayName="Channels Per Node" hpcc:group="Redundancy" use="optional" default="1" hpcc:tooltip="Number of channels/data locations to use per node, in overloaded mode"/>
+                    <xs:attribute name="numDataCopies" type="xs:nonNegativeInteger" hpcc:displayName="Number Data Copies" hpcc:group="Redundancy" use="optional" default="1" hpcc:tooltip="Number of copies of the data in redundant modes"/>
+                    <xs:attribute name="slaveConfig" hpcc:displayName="Slave Config" hpcc:group="Redundancy" use="optional" default="" hpcc:tooltip="Roxie data redundancy mode"/>
+                        <xs:simpleType>
+                            <xs:restriction base="xs:string">
+                                <xs:enumeration value="simple" hpcc:displayName="Simple" hpcc:description=""/>
+                                <xs:enumeration value="overloaded" hpcc:displayName="Overloaded" hpcc:description=""/>
+                                <xs:enumeration value="full redundancy" hpcc:displayName="Full Redundancy" hpcc:description=""/>
+                                <xs:enumeration value="cyclic redundancy" hpcc:displayName="Cyclic Redundancy" hpcc:description=""/>
+                            </xs:restriction>
+                        </xs:simpleType>
+                    </xs:attribute>
+                    <!-- Tracing attributes -->
+                    <xs:attribute name="traceLevel" type="xs:nonNegativeInteger" hpcc:displayName="Trace Level" hpcc:group="Tracing"use="optional" default="1" hpcc:tooltip="Level of detail in reporting (set to 0 for none, 1 for normal, > 1 or more for extended)"/>
+                    <xs:attribute name="logFullQueries" type="xs:boolean" hpcc:displayName="Log Full Queries" hpcc:group="Tracing" use="optional" default="false" hpcc:tooltip="Log full text (unless blindLogging) and resource usage of all queries received"/>
+                    <xs:attribute name="blindLogging" type="xs:boolean" hpcc:displayName="Blind Logging" hpcc:group="Tracing" use="optional" default="false" hpcc:tooltip="Suppress all logging of any data or query text"/>
+                    <xs:attribute name="memTraceLevel" type="xs:nonNegativeInteger" hpcc:displayName="Memory Trace Level" hpcc:group="Tracing" use="optional" default="1" hpcc:tooltip="Level of detail in reporting mem mgr information(set to 0 for none, 1 for normal, >1 or more for extended)"/>
+                    <xs:attribute name="miscDebugTraceLevel" type="xs:nonNegativeInteger" hpcc:displayName="Misc Debug Trace Level" hpcc:group="Tracing" use="optional" default="0" hpcc:tooltip="Level of miscellaneous debug tracing unrelated to all other tracing(set to 0 for none, 1 for normal, >1 or more for extended)"/>
+                    <xs:attribute name="soapTraceLevel" type="xs:nonNegativeInteger" hpcc:displayName="Soap trace Level" hpcc:group="Tracing" use="optional" default="1" hpcc:tooltip="Level of detail in reporting SOAPCALL information(set to 0 for none, 1 for normal, >1 or more for extended)"/>
+                    <xs:attribute name="traceEnabled" type="xs:boolean" hpcc:displayName="Trace Enabled" hpcc:group="Tracing" use="optional" default="false" hpcc:tooltip="TRACE activity output enabled by default (can be overridden in workunit or query)"/>
+                    <xs:attribute name="traceLimit" type="xs:nonNegativeInteger" hpcc:displayName="Trace Limit" hpcc:group="Tracing" use="optional" default="10" hpcc:tooltip="Number of rows output by TRACE activity"/>
+                    <xs:attribute name="udpTraceLevel" type="xs:nonNegativeInteger" hpcc:displayName="UDP Trace Level" hpcc:group="Tracing" use="optional" default="1" hpcc:tooltip="Level of detail in reporting udp information(set to 0 for none, 1 for normal, >1 or more for extended)"/>
+                    <xs:attribute name="useLogQueue" type="xs:boolean" hpcc:displayName="Use Log Queue" hpcc:group="Tracing" use="optional" default="true" hpcc:tooltip="Queue logs messages"/>
+                    <xs:attribute name="logQueueDrop" type="xs:nonNegativeInteger" hpcc:displayName="Log Queue Drop" hpcc:group="Tracing" use="optional" default="32" hpcc:tooltip="Specifies the number of log messages which will be dropped if the maximum length of the queue of unhandled messages is exceeded"/>
+                    <xs:attribute name="logQueueLen" type="xs:nonNegativeInteger" hpcc:displayName="Log Queue Length" hpcc:group="Tracing" use="optional" default="512" hpcc:tooltip="Specifies the maximum length of the queue of unhandled log messages. Messages will be dropped if this is exceeded"/>
+                    <!-- UDP attributes -->
+                    <xs:attribute name="roxieMulticastEnabled" type="xs:boolean" hpcc:displayName="Enable Roxie Multicast" hpcc:group="UDP" use="optional" default="true" hpcc:tooltip="Controls whether multicast is used to communicate between nodes"/>
+                    <xs:attribute name="udpFlowSocketsSize" type="xs:nonNegativeInteger" hpcc:displayName="UDP Flow Socket Size (bytes)" hpcc:group="UDP" use="optional" default="131071" hpcc:tooltip="Controls the read socket buffer size of the UDP layer flow control sockets"/>
+                    <xs:attribute name="udpInlineCollation" type="xs:boolean" hpcc:displayName="UDP Inline Collation" hpcc:group="UDP" use="optional" default="false" hpcc:tooltip="Controls whether UDP packets are collated on the reading thread or queued up for collation on a separate thread"/>
+                    <xs:attribute name="udpInlineCollationPacketLimit" type="xs:nonNegativeInteger" hpcc:displayName="UDP Inline Colation Packet Limit" hpcc:group="UDP" use="optional" default="50" hpcc:tooltip="Controls how many UDP packets requested at once when inline collation selected"/>
+                    <xs:attribute name="udpLocalWriteSocketSize" type="xs:nonNegativeInteger" hpcc:displayName="UDP Local Write Socket Size (bytes)" hpcc:group="UDP" use="optional" default="131071" hpcc:tooltip="Controls the write socket buffer size of the local UDP sockets (Agent to Server on same node)"/>
+                    <xs:attribute name="udpMaxRetryTimedoutReqs" type="xs:nonNegativeInteger" hpcc:displayName="UDP Max Retry Timedout Reqs" hpcc:group="UDP" use="optional" default="0" hpcc:tooltip="Controls the Max number of agent "request to send" to be retried. 0 means keep retrying forever"/>
+                    <xs:attribute name="udpMaxSlotsPerClient" type="xs:nonNegativeInteger" hpcc:displayName="Log Queue Length" hpcc:group="UDP" use="optional" default="2147483647" hpcc:tooltip="UDP transport layer slots per client"/>
+                    <xs:attribute name="udpMulticastBufferSize" type="xs:nonNegativeInteger" hpcc:displayName="UDP Multicast Buffer Size (bytes)" hpcc:group="UDP" use="optional" default="131071" hpcc:tooltip="Controls the read socket buffer size of the UDP multicast sockets"/>
+                    <xs:attribute name="udpOutQsPriority" type="xs:nonNegativeInteger" hpcc:displayName="UDP Quality of Service Priority" hpcc:group="UDP" use="optional" default="0" hpcc:tooltip="Turns on/off Priority weight-based for output queues (0 round-robin no priority - old logic, 1 round-robin new logic, 2 and higher is factor of priority)"/>
+                    <xs:attribute name="udpQueueSize" type="xs:nonNegativeInteger" hpcc:displayName="UDP Queue Size" hpcc:group="UDP" use="optional" default="100" hpcc:tooltip="UDP transport layer receive queue size"/>
+                    <xs:attribute name="udpRequestToSendTimeout" type="xs:nonNegativeInteger" hpcc:displayName="UDP Request To Send Timeout (units?)" hpcc:group="UDP" use="optional" default="0" hpcc:tooltip="Controls the timeout value agent udp will wait for permission to send from a Roxie server, in milliseconds. Specify 0 to calcuate automatically"/>
+                    <xs:attribute name="udpResendEnabled" type="xs:boolean" hpcc:displayName="Enable UDP Resend" hpcc:group="UDP" use="optional" default="false" hpcc:tooltip="UDP transport layer packet resend ability"/>
+                    <xs:attribute name="udpRetryBusySenders" type="xs:nonNegativeInteger" hpcc:displayName="UDP Retry Busy Senders" hpcc:group="UDP" use="optional" default="0" hpcc:tooltip="Controls the number of times Roxie server will repeat search for an idle sender when requesting new data"/>
+                    <xs:attribute name="udpSendQueueSize" type="xs:nonNegativeInteger" hpcc:displayName="UDP Send Queue Size" hpcc:group="UDP" use="optional" default="50" hpcc:tooltip="UDP transport layer send queue size"/>
+                    <xs:attribute name="udpSnifferEnabled" type="xs:boolean" hpcc:displayName="Enable UDP Sniffer" hpcc:group="UDP" use="optional" default="true" hpcc:tooltip="Enable the UDP multicast sniffer for tracking which senders are busy"/>
+                    <xs:attribute name="udpSnifferReadThreadPriority" type="nonNegativeInteger" hpcc:displayName="UDP Sniffer Read Thread Priority" hpcc:group="UDP" use="optional" default="3" hpcc:tooltip="If non-zero, run the sniffer read thread at elevated priority level"/>
+                    <xs:attribute name="udpSnifferSendThreadPriority" type="nonNegativeInteger" hpcc:displayName="UDP Sniffer Send Thread Priority" hpcc:group="UDP" use="optional" default="3" hpcc:tooltip="If non-zero, run the sniffer send thread at elevated priority level"/>
+                    <!-- Cache attributes -->
+                    <xs:attribute name="blobCacheMem" type="xs:nonNegativeInteger" hpcc:displayName="Blob Cache Memory Size (Mb)" hpcc:group="Cache" use="optional" default="0" hpcc:tooltip="Size (in Mb) of blob index page cache"/>
+                    <xs:attribute name="serverSideCacheSize" type="xs:nonNegativeInteger" hpcc:displayName="Server Side Cache Size" hpcc:group="Cache" use="optional" default="0" hpcc:tooltip="Number of agent results to cache on Roxie server"/>
+                    <xs:attribute name="leafCacheMem" type="xs:nonNegativeInteger" hpcc:displayName="Leaf Cache Memory Size (Mb)" hpcc:group="Cache" use="optional" default="50" hpcc:tooltip="Size (in Mb) of leaf index page cache"/>
+                    <xs:attribute name="nodeCachePreload" type="xs:boolean" hpcc:displayName="Enable Node Cache Preload" hpcc:group="Cache" use="optional" default="false" hpcc:tooltip="Prefill the node cache with all non-leaf pages from all indexes"/>
+                    <xs:attribute name="nodeCacheMem" type="xs:nonNegativeInteger" hpcc:displayName="Node Cache Memory Size (Mb)" hpcc:group="Cache" use="optional" default="100" hpcc:tooltip="Size (in Mb) of non-leaf index page cache"/>
+                    <!-- SSH attributes Options for using remote SSH execution -->
+                    <xs:attribute name="SSHidentityfile" type="absolutePath" hpcc:displayName="SSH IdentityFile" hpcc:group="SSH" use="optional" default="$HOME/.ssh/id_rsa" hpcc:tooltip="location of identity file (private key) on Thor master"/>
+                    <xs:attribute name="SSHusername" type="xs:string" hpcc:displayName="SSH Username" hpcc:group="SSH" use="optional" default="hpcc" hpcc:tooltip="Username to use when running Thor slaves"/>
+                    <xs:attribute name="SSHpassword" type="xs:string" hpcc:modifiers="mask,verify" hpcc:displayName="SSH Password" hpcc:group="SSH" use="optional" default="" hpcc:tooltip="Fixed password - only required if no identity file present NB **insecure**"/>
+                    <!-- required if username set? -->
+                    <xs:attribute name="SSHtimeout" type="xs:nonNegativeInteger" hpcc:displayName="SSH Timeout (s)" hpcc:group="SSH" use="optional" default="0" hpcc:tooltip="Timeout in seconds for SSH connects"/>
+                    <xs:attribute name="SSHretries" type="xs:nonNegativeInteger" hpcc:displayName="SSH Retries" hpcc:group="SSH" use="optional" default="3" hpcc:tooltip="Number of times to retry failed connect"/>
+                    <!-- Ports attribute group removed, was no longer used -->
+                    <!-- Debug attributes -->
+                    <xs:attribute name="checkCompleted" type="xs:boolean" hpcc:displayName="Check Completed" hpcc:group="Debug" use="optional" default="true" hpcc:tooltip="Check pending replies when agent gets a retry request"/>
+                    <xs:attribute name="dafilesrvLookupTimeout" type="xs:nonNegativeInteger" hpcc:displayName="DaFileserv Lookup Timeout (ms)" hpcc:group="Debug" use="optional" default="10000" hpcc:tooltip="Maximum time (in milliseconds) dafilesrv will wait before timing out the first time through the list"/>
+                    <xs:attribute name="defaultConcatPreload" type="xs:nonNegativeInteger" hpcc:displayName="Default Concat Preload" hpcc:group="Debug" use="optional" default="0" hpcc:tooltip="Default concat preloa"/>
+                    <xs:attribute name="defaultFetchPreload" type="xs:nonNegativeInteger" hpcc:displayName="Default Fetch Preload" hpcc:group="Debug" use="optional" default="0" hpcc:tooltip="Default fetch preload"/>
+                    <xs:attribute name="defaultFullKeyedJoinPreload" type="xs:nonNegativeInteger" hpcc:displayName="Default Full Keyed Join Preload" hpcc:group="Debug" use="optional" default="0" hpcc:tooltip="Default full keyed join preload"/>
+                    <xs:attribute name="defaultKeyedJoinPreload" type="xs:nonNegativeInteger" hpcc:displayName="Default Keyed Join Preload" hpcc:group="Debug" use="optional" default="0" hpcc:tooltip="Default keyed join preload"/>
+                    <xs:attribute name="defaultParallelJoinPreload" type="xs:nonNegativeInteger" hpcc:displayName="Default Parallel Join Preload" hpcc:group="Debug" use="optional" default="0" hpcc:tooltip="Default parallel join preload"/>
+                    <xs:attribute name="defaultPrefetchProjectPreload" type="xs:nonNegativeInteger" hpcc:displayName="Default Prefetch Project Preload" hpcc:group="Debug" use="optional" default="10" hpcc:tooltip="Default prefetch value for PROJECT,PREFETCH activity"/>
+                    <xs:attribute name="diskReadBufferSize" type="xs:nonNegativeInteger" hpcc:displayName="Disk Read Buffer Size (bytes)" hpcc:group="Debug" use="optional" default="65536" hpcc:tooltip="Default buffer size for disk read operations"/>
+                    <xs:attribute name="doIbytiDelay" type="xs:boolean" hpcc:displayName="Enable IBYTI Ddelay Logic" hpcc:group="Debug" use="optional" default="true" hpcc:tooltip="Enables the IBYTI delay logic in the agents"/>
+                    <xs:attribute name="enableHeartBeat" type="xs:boolean" hpcc:displayName="Enable Heartbeat" hpcc:group="Debug" use="optional" default="true" hpcc:tooltip="Enable HeartBeat messages to clients"/>
+                    <xs:attribute name="fastLaneQueue" type="xs:boolean" hpcc:displayName="Enable Fast Lane Queue" hpcc:group="Debug" use="optional" default="true" hpcc:tooltip="special fast-lane queue for simple queries"/>
+                    <xs:attribute name="forceStdLog" type="xs:boolean" hpcc:displayName="Force Std Log Output" hpcc:group="Debug" use="optional" default="false" hpcc:tooltip="Force log output to stderr even when redirected to null"/>
+                    <xs:attribute name="ignoreMissingFiles" type="xs:boolean" hpcc:displayName="Ignore Missing Files" hpcc:group="Debug" use="optional" default="false" hpcc:tooltip="Ignore missing files"/>
+                    <xs:attribute name="indexReadChunkSize" type="xs:nonNegativeInteger" hpcc:displayName="Index Read Chunk Size" hpcc:group="Debug" use="optional" default="60000" hpcc:tooltip="Break up results from indexRead (and other remote activities) every N bytes"/>
+                    <xs:attribute name="initIbytiDelay" type="xs:nonNegativeInteger" hpcc:displayName="Init IBYTI Delay Time (ms)" hpcc:group="Debug" use="optional" default="100" hpcc:tooltip="Initial time (in milliseconds) a secondary agent will wait for an IBYTI packet from a primary peer"/>
+                    <xs:attribute name="jumboFrames" type="xs:boolean" hpcc:displayName="Jumbo Frames" hpcc:group="Debug" use="optional" default="false" hpcc:tooltip="Set to true if using jumbo frames (MTU=9000) on the network"/>
+                    <xs:attribute name="linuxYield" type="xs:boolean" hpcc:displayName="Linux Yield" hpcc:group="Debug" use="optional" default="false" hpcc:tooltip="Yield to scheduler in some tight loops. May help latency on uniprocessor machines"/>
+                    <xs:attribute name="maxBlockSize" type="xs:nonNegativeInteger" hpcc:displayName="Maximum Block Size (bytes)" hpcc:group="Debug" use="optional" default="10000000" hpcc:tooltip="Max size of block read from client socket"/>
+                    <xs:attribute name="maxLockAttempts" type="xs:nonNegativeInteger" hpcc:displayName="Maximum Lock Attempts" hpcc:group="Debug" use="optional" default="5" hpcc:tooltip="Number of retries to get lock for global queries"/>
+                    <xs:attribute name="memoryStatsInterval" type="xs:nonNegativeInteger" hpcc:displayName="Memory Stats Interval (s)" hpcc:group="Debug" use="optional" default="60" hpcc:tooltip="Interval (in seconds) between reports on Roxie heap usage"/>
+                    <xs:attribute name="memTraceSizeLimit" type="xs:nonNegativeInteger" hpcc:displayName="Memory trace Size Limit (bytes?)" hpcc:group="Debug" use="optional" default="0" hpcc:tooltip="Generate stacktrace whenever a request is made for a row larger than this threshold (0 to disable)"/>
+                    <xs:attribute name="parallelAggregate" type="xs:nonNegativeInteger" hpcc:displayName="Parallel Aggregate" hpcc:group="Debug" use="optional" default="0" hpcc:tooltip="Number of parallel threads to use for in-memory aggregate processing. Set to 0 to use one per CPU, 1 to disable parallel processing of in-memory aggregates"/>
+                    <xs:attribute name="perChannelFlowLimit" type="xs:nonNegativeInteger" hpcc:displayName="Per Channel Flow Limit" hpcc:group="Debug" use="optional" default="10" hpcc:tooltip="Number of pending queries permitted per channel (per active activity) before blocking"/>
+                    <xs:attribute name="pingInterval" type="xs:nonNegativeInteger" hpcc:displayName="Ping Interval (s)" hpcc:group="Debug" use="optional" default="60" hpcc:tooltip="Interval (in seconds) between Roxie server ping tests"/>
+                    <xs:attribute name="preabortIndexReadsThreshold" type="xs:nonNegativeInteger" hpcc:displayName="Pre Abort Index Reads Threshold" hpcc:group="Debug" use="optional" default="100" hpcc:tooltip="Use seek to precheck keyed limits (i.e. assume ,COUNT) on index reads if limit greater than this value"/>
+                    <xs:attribute name="preabortKeyedJoinsThreshold" type="xs:nonNegativeInteger" hpcc:displayName="Pre Abort Keyed Joins Threshold" hpcc:group="Debug" use="optional" default="100" hpcc:tooltip="Use seek to precheck limits on keyed joins if limit greater than this value"/>
+                    <xs:attribute name="simpleLocalKeyedJoins" type="xs:boolean" hpcc:displayName="Simple Local Keyed Joins" hpcc:group="Debug" use="optional" default="true" hpcc:tooltip="Enable single-threaded local keyed joins"/>
+                    <xs:attribute name="socketCheckInterval" type="xs:nonNegativeInteger" hpcc:displayName="Socket Check Interval" hpcc:group="Debug" use="optional" default="5000" hpcc:tooltip="Interval (in milliseconds) between checks that client socket is still open"/>
+                    <xs:attribute name="systemMonitorInterval" type="xs:nonNegativeInteger" hpcc:displayName="System Monitor Interval (ms?)" hpcc:group="Debug" use="optional" default="60000" hpcc:tooltip="How often to send an 'alive' message"/>
+                </xs:complexType>
+                <xs:key name="roxieCluster_namekey">
+                    <xs:selector xpath="."/>
+                    <xs:field xpath="@name"/>
+                </xs:key>
+                <xs:keyref name="roxisServerProcess_Instance_nameref" refer="computerNameKey">
+                    <xs:selector xpath="RoxieServerProcess"/>
+                    <xs:field xpath="@name"/>
+                </xs:keyref>
+                <xs:keyref name="roxisServerProcess_Instance_computerref" refer="computerNameKey">
+                    <xs:selector xpath="RoxieServerProcess"/>
+                    <xs:field xpath="@computer"/>
+                </xs:keyref>
+                <xs:keyref name="roxisServerProcess_Instance_ipref" refer="computerIPAddressKey">
+                    <xs:selector xpath="RoxieServerProcess"/>
+                    <xs:field xpath="@netAddress"/>
+                </xs:keyref>
+                <xs:key name="roxie_ACLName">
+                    <xs:selector xpath="ACL"/>
+                    <xs:field xpath="@name"/>
+                </xs:key>
+                <xs:keyref name="roxie_ACLBaselistref" refer="roxie_ACLName">
+                    <xs:selector xpath="ACL/BaseList"/>
+                    <xs:field xpath="@name"/>
+                </xs:keyref>
+                <xs:key name="roxie_ACLAccessName">
+                    <xs:selector xpath="ACL/Access"/>
+                    <xs:field xpath="@name"/>
+                </xs:key>
+                <xs:key name="roxie_PreferredClusterName">
+                    <xs:selector xpath="PreferredCluster"/>
+                    <xs:field xpath="@name"/>
+                </xs:key>
+                <xs:key name="roxie_UserMetricName">
+                    <xs:selector xpath="UserMetric"/>
+                    <xs:field xpath="@name"/>
+                </xs:key>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+</xs:schema>

+ 53 - 14
initfiles/componentfiles/config2xml/types.xsd

@@ -25,61 +25,99 @@
             <xs:maxInclusive value="100"/>
         </xs:restriction>
     </xs:simpleType>
+
+    <xs:simpleType name="yesno">
+        <xs:restriction base="xs:string">
+            <xs:minInclusive value="yes" hpcc:displayName="Yes"/>
+            <xs:maxInclusive value="no" hpcc:displayName="No"/>
+        </xs:restriction>
+    </xs:simpleType>
+
     <xs:simpleType name="nodeName">
         <xs:restriction base="xs:string">
             <xs:pattern value="[a-zA-z0-9_\-]+"/>
             <!-- need regex to eliminate special characters -->
         </xs:restriction>
     </xs:simpleType>
+
     <xs:simpleType name="version">
         <xs:restriction base="xs:string">
             <xs:pattern value=""/>
             <!-- regex for d[.d[.d[.d]]] -->
         </xs:restriction>
     </xs:simpleType>
+
     <xs:simpleType name="ipV4Address">
         <xs:restriction base="xs:token">
             <xs:pattern value="/^0*([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.0*([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.0*([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.0*([1-9]?\\d|1\\d\\d|2[0-4]\\d|25[0-5])$/"/>
         </xs:restriction>
     </xs:simpleType>
+
     <xs:simpleType name="absolutePath">
         <xs:restriction base="xs:string">
             <xs:pattern value="/^\\/.*/"/>
         </xs:restriction>
     </xs:simpleType>
+
+    <xs:simpleType name="relativePath">
+        <xs:restriction base="xs:string">
+            <!-- xs:pattern value="/^\\/.*/"/   Need one! -->
+        </xs:restriction>
+    </xs:simpleType>
+
     <xs:simpleType name="AutoTimeStampType">
         <xs:restriction base="xs:string" hpcc:autoType="timestamp"/>
     </xs:simpleType>
+
     <xs:simpleType name="AutoComputerType">
         <xs:restriction base="xs:string" hpcc:autoType="requestIP"/>
     </xs:simpleType>
+
     <xs:simpleType name="AutoUseridType">
         <xs:restriction base="xs:string" hpcc:autoType="requestUser"/>
     </xs:simpleType>
+
     <xs:attributeGroup name="computerNode">
         <xs:attribute name="name" type="nodeName" use="required"/>
         <xs:attribute name="netAddress" type="ipV4Address" use="required"/>
     </xs:attributeGroup>
+
     <xs:attributeGroup name="computerNodeReference">
         <xs:attribute name="computer" type="nodeName" use="required" hpcc:readOnly="true" hpcc:mirrorFrom="/Environment/Hardware/Computer@name"/>
         <xs:attribute name="netAddress" type="ipV4Address" use="required" hpcc:readOnly="true" hpcc:mirrorFrom="/Environment/Hardware/Computer@netAddress"/>
     </xs:attributeGroup>
-    <xs:complexType name="usernotes">
+
+    <xs:complexType name="hwinstance">
         <xs:sequence>
-            <xs:element name="Note" type="xs:string" minOccurs="0"/>
+            <xs:element name="Instance" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attributeGroup ref="computerNodeReference"/>
+                </xs:complexType>
+            </xs:element>
         </xs:sequence>
-        <xs:attribute name="severity" use="optional" default="Minor" hpcc:displayName="Severity" hpcc:tooltip="Significance of this note">
-            <xs:simpleType>
-                <xs:restriction base="xs:string">
-                    <xs:enumeration value="Minor"/>
-                    <xs:enumeration value="Normal"/>
-                    <xs:enumeration value="Critical"/>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-        <xs:attribute name="date" type="AutoTimeStampType" use="optional" hpcc:displayName="Date/Time" hpcc:readOnly="true" hpcc:tooltip="Date and time this note was entered"/>
-        <xs:attribute name="computer" type="AutoComputerType" use="optional" hpcc:displayName="Computer" hpcc:readOnly="true" hpcc:tooltip="Computer from which this note was entered"/>
-        <xs:attribute name="user" type="AutoUseridType" use="optional" hpcc:displayName="User" hpcc:readOnly="true" hpcc:tooltip="User account from which this note was entered"/>
+    </xs:complexType>
+
+    <xs:complexType name="usernotes">
+        <xs:seqeunce>
+            <xs:element name="Notes" maxOccurs="unbounded"/>
+            <xs:complexType>
+                <xs:sequence>
+                    <xs:element name="Note" type="xs:string" minOccurs="0"/>
+                </xs:sequence>
+                <xs:attribute name="severity" use="optional" default="Minor" hpcc:displayName="Severity" hpcc:tooltip="Significance of this note">
+                    <xs:simpleType>
+                        <xs:restriction base="xs:string">
+                            <xs:enumeration value="Minor"/>
+                            <xs:enumeration value="Normal"/>
+                            <xs:enumeration value="Critical"/>
+                        </xs:restriction>
+                    </xs:simpleType>
+                </xs:attribute>
+                <xs:attribute name="date" type="AutoTimeStampType" use="optional" hpcc:displayName="Date/Time" hpcc:readOnly="true" hpcc:tooltip="Date and time this note was entered"/>
+                <xs:attribute name="computer" type="AutoComputerType" use="optional" hpcc:displayName="Computer" hpcc:readOnly="true" hpcc:tooltip="Computer from which this note was entered"/>
+                <xs:attribute name="user" type="AutoUseridType" use="optional" hpcc:displayName="User" hpcc:readOnly="true" hpcc:tooltip="User account from which this note was entered"/>
+            </xs:complexType>
+        </xs:seqeunce>
     </xs:complexType>
 
     <xs:complexType name="espservice_properties">
@@ -146,6 +184,7 @@
             </xs:element>
         </xs:sequence>
     </xs:complexType>
+
     <xs:attributeGroup name="buildInfo">
         <xs:attribute name="build" type="xs:string" use="required" hpcc:hidden="true" hpcc:autoGenerateType="fixedValue" hpcc:autoGenerateValue="_"/>
         <xs:attribute name="buildSet" type="xs:string" use="required" hpcc:hidden="true" hpcc:autoGenerateType="configProperty" hpcc:autoGenerateValue="componentName"/>