Add TaskEvent registry

This updates the parse registries script and
adds the task registry to be used by task service.
This templates the original Base Registry so it
can be reused for all registries.

Tested: script works, validator passes

Change-Id: Id1cf3a41fb76ccaadace114725480f410bfba3e8
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 6c8be39..aacfda0 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -149,10 +149,8 @@
 
         nodes.emplace_back(
             std::make_unique<MessageRegistryFileCollection>(app));
-        nodes.emplace_back(std::make_unique<BaseMessageRegistryFile>(app));
-        nodes.emplace_back(std::make_unique<BaseMessageRegistry>(app));
-        nodes.emplace_back(std::make_unique<OpenBMCMessageRegistryFile>(app));
-        nodes.emplace_back(std::make_unique<OpenBMCMessageRegistry>(app));
+        nodes.emplace_back(std::make_unique<MessageRegistryFile>(app));
+        nodes.emplace_back(std::make_unique<MessageRegistry>(app));
         nodes.emplace_back(std::make_unique<CertificateService>(app));
         nodes.emplace_back(
             std::make_unique<CertificateActionsReplaceCertificate>(app));
diff --git a/redfish-core/include/registries/base_message_registry.hpp b/redfish-core/include/registries/base_message_registry.hpp
index f9009f1..6290198 100644
--- a/redfish-core/include/registries/base_message_registry.hpp
+++ b/redfish-core/include/registries/base_message_registry.hpp
@@ -1,5 +1,5 @@
 /*
-// Copyright (c) 2019 Intel Corporation
+// Copyright (c) 2020 Intel Corporation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -33,6 +33,9 @@
     "1.4.0",
     "DMTF",
 };
+constexpr const char* url =
+    "https://redfish.dmtf.org/registries/Base.1.4.0.json";
+
 constexpr std::array<MessageEntry, 58> registry = {
     MessageEntry{
         "AccessDenied",
diff --git a/redfish-core/include/registries/task_event_message_registry.hpp b/redfish-core/include/registries/task_event_message_registry.hpp
new file mode 100644
index 0000000..a2e3a89
--- /dev/null
+++ b/redfish-core/include/registries/task_event_message_registry.hpp
@@ -0,0 +1,143 @@
+/*
+// Copyright (c) 2020 Intel Corporation
+//
+// 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.
+*/
+/****************************************************************
+ * This is an auto-generated header which contains definitions
+ * for Redfish DMTF defined messages.
+ ***************************************************************/
+#pragma once
+#include <registries.hpp>
+
+namespace redfish::message_registries::task_event
+{
+const Header header = {
+    "Copyright 2014-2018 DMTF in cooperation with the Storage Networking "
+    "Industry Association (SNIA). All rights reserved.",
+    "#MessageRegistry.v1_2_0.MessageRegistry",
+    "TaskEvent.1.0.1",
+    "Task Event Message Registry",
+    "en",
+    "This registry defines the messages for task related events.",
+    "TaskEvent",
+    "1.0.1",
+    "DMTF",
+};
+constexpr const char* url =
+    "https://redfish.dmtf.org/registries/TaskEvent.1.0.1.json";
+
+constexpr std::array<MessageEntry, 9> registry = {
+    MessageEntry{"TaskAborted",
+                 {
+                     "The task with id %1 has been aborted.",
+                     "The task with id %1 has been aborted.",
+                     "Critical",
+                     1,
+                     {
+                         "string",
+                     },
+                     "None.",
+                 }},
+    MessageEntry{"TaskCancelled",
+                 {
+                     "The task with id %1 has been cancelled.",
+                     "The task with id %1 has been cancelled.",
+                     "Warning",
+                     1,
+                     {
+                         "string",
+                     },
+                     "None.",
+                 }},
+    MessageEntry{"TaskCompletedOK",
+                 {
+                     "The task with id %1 has completed.",
+                     "The task with id %1 has completed.",
+                     "OK",
+                     1,
+                     {
+                         "string",
+                     },
+                     "None.",
+                 }},
+    MessageEntry{"TaskCompletedWarning",
+                 {
+                     "The task with id %1 has completed with warnings.",
+                     "The task with id %1 has completed with warnings.",
+                     "Warning",
+                     1,
+                     {
+                         "string",
+                     },
+                     "None.",
+                 }},
+    MessageEntry{"TaskPaused",
+                 {
+                     "The task with id %1 has been paused.",
+                     "The task with id %1 has been paused.",
+                     "Warning",
+                     1,
+                     {
+                         "string",
+                     },
+                     "None.",
+                 }},
+    MessageEntry{
+        "TaskProgressChanged",
+        {
+            "The task with id %1 has changed to progress %2 percent complete.",
+            "The task with id %1 has changed to progress %2 percent complete.",
+            "OK",
+            2,
+            {
+                "string",
+                "number",
+            },
+            "None.",
+        }},
+    MessageEntry{"TaskRemoved",
+                 {
+                     "The task with id %1 has been removed.",
+                     "The task with id %1 has been removed.",
+                     "Warning",
+                     1,
+                     {
+                         "string",
+                     },
+                     "None.",
+                 }},
+    MessageEntry{"TaskResumed",
+                 {
+                     "The task with id %1 has been resumed.",
+                     "The task with id %1 has been resumed.",
+                     "OK",
+                     1,
+                     {
+                         "string",
+                     },
+                     "None.",
+                 }},
+    MessageEntry{"TaskStarted",
+                 {
+                     "The task with id %1 has started.",
+                     "The task with id %1 has started.",
+                     "OK",
+                     1,
+                     {
+                         "string",
+                     },
+                     "None.",
+                 }},
+};
+} // namespace redfish::message_registries::task_event
diff --git a/redfish-core/lib/message_registries.hpp b/redfish-core/lib/message_registries.hpp
index 628c63a..7c957e9 100644
--- a/redfish-core/lib/message_registries.hpp
+++ b/redfish-core/lib/message_registries.hpp
@@ -19,6 +19,7 @@
 #include "registries.hpp"
 #include "registries/base_message_registry.hpp"
 #include "registries/openbmc_message_registry.hpp"
+#include "registries/task_event_message_registry.hpp"
 
 namespace redfish
 {
@@ -55,21 +56,22 @@
             {"@odata.id", "/redfish/v1/Registries"},
             {"Name", "MessageRegistryFile Collection"},
             {"Description", "Collection of MessageRegistryFiles"},
-            {"Members@odata.count", 2},
+            {"Members@odata.count", 3},
             {"Members",
              {{{"@odata.id", "/redfish/v1/Registries/Base"}},
+              {{"@odata.id", "/redfish/v1/Registries/TaskEvent"}},
               {{"@odata.id", "/redfish/v1/Registries/OpenBMC"}}}}};
 
         res.end();
     }
 };
 
-class BaseMessageRegistryFile : public Node
+class MessageRegistryFile : public Node
 {
   public:
     template <typename CrowApp>
-    BaseMessageRegistryFile(CrowApp &app) :
-        Node(app, "/redfish/v1/Registries/Base/")
+    MessageRegistryFile(CrowApp &app) :
+        Node(app, "/redfish/v1/Registries/<str>/", std::string())
     {
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
@@ -84,31 +86,74 @@
     void doGet(crow::Response &res, const crow::Request &req,
                const std::vector<std::string> &params) override
     {
+        if (params.size() != 1)
+        {
+            messages::internalError(res);
+            res.end();
+            return;
+        }
+
+        const std::string &registry = params[0];
+        const message_registries::Header *header;
+        std::string dmtf = "DMTF ";
+        const char *url = nullptr;
+
+        if (registry == "Base")
+        {
+            header = &message_registries::base::header;
+            url = message_registries::base::url;
+        }
+        else if (registry == "TaskEvent")
+        {
+            header = &message_registries::task_event::header;
+            url = message_registries::task_event::url;
+        }
+        else if (registry == "OpenBMC")
+        {
+            header = &message_registries::openbmc::header;
+            dmtf.clear();
+        }
+        else
+        {
+            messages::resourceNotFound(
+                res, "#MessageRegistryFile.v1_1_0.MessageRegistryFile",
+                registry);
+            res.end();
+            return;
+        }
+
         res.jsonValue = {
-            {"@odata.id", "/redfish/v1/Registries/Base"},
+            {"@odata.id", "/redfish/v1/Registries/" + registry},
             {"@odata.type", "#MessageRegistryFile.v1_1_0.MessageRegistryFile"},
-            {"Name", "Base Message Registry File"},
-            {"Description", "DMTF Base Message Registry File Location"},
-            {"Id", message_registries::base::header.registryPrefix},
-            {"Registry", message_registries::base::header.id},
+            {"Name", registry + " Message Registry File"},
+            {"Description",
+             dmtf + registry + " Message Registry File Location"},
+            {"Id", header->registryPrefix},
+            {"Registry", header->id},
             {"Languages", {"en"}},
             {"Languages@odata.count", 1},
             {"Location",
              {{{"Language", "en"},
-               {"PublicationUri",
-                "https://redfish.dmtf.org/registries/Base.1.4.0.json"},
-               {"Uri", "/redfish/v1/Registries/Base/Base"}}}},
+               {"Uri",
+                "/redfish/v1/Registries/" + registry + "/" + registry}}}},
             {"Location@odata.count", 1}};
+
+        if (url != nullptr)
+        {
+            res.jsonValue["Location"][0]["PublicationUri"] = url;
+        }
+
         res.end();
     }
 };
 
-class BaseMessageRegistry : public Node
+class MessageRegistry : public Node
 {
   public:
     template <typename CrowApp>
-    BaseMessageRegistry(CrowApp &app) :
-        Node(app, "/redfish/v1/Registries/Base/Base/")
+    MessageRegistry(CrowApp &app) :
+        Node(app, "/redfish/v1/Registries/<str>/<str>/", std::string(),
+             std::string())
     {
         entityPrivileges = {
             {boost::beast::http::verb::get, {{"Login"}}},
@@ -123,34 +168,86 @@
     void doGet(crow::Response &res, const crow::Request &req,
                const std::vector<std::string> &params) override
     {
-        res.jsonValue = {
-            {"@Redfish.Copyright", message_registries::base::header.copyright},
-            {"@odata.type", message_registries::base::header.type},
-            {"Id", message_registries::base::header.id},
-            {"Name", message_registries::base::header.name},
-            {"Language", message_registries::base::header.language},
-            {"Description", message_registries::base::header.description},
-            {"RegistryPrefix", message_registries::base::header.registryPrefix},
-            {"RegistryVersion",
-             message_registries::base::header.registryVersion},
-            {"OwningEntity", message_registries::base::header.owningEntity}};
+        if (params.size() != 2)
+        {
+            messages::internalError(res);
+            res.end();
+            return;
+        }
+
+        const std::string &registry = params[0];
+        const std::string &registry1 = params[1];
+
+        const message_registries::Header *header;
+        std::vector<const message_registries::MessageEntry *> registryEntries;
+        if (registry == "Base")
+        {
+            header = &message_registries::base::header;
+            for (const message_registries::MessageEntry &entry :
+                 message_registries::base::registry)
+            {
+                registryEntries.emplace_back(&entry);
+            }
+        }
+        else if (registry == "TaskEvent")
+        {
+            header = &message_registries::task_event::header;
+            for (const message_registries::MessageEntry &entry :
+                 message_registries::task_event::registry)
+            {
+                registryEntries.emplace_back(&entry);
+            }
+        }
+        else if (registry == "OpenBMC")
+        {
+            header = &message_registries::openbmc::header;
+            for (const message_registries::MessageEntry &entry :
+                 message_registries::openbmc::registry)
+            {
+                registryEntries.emplace_back(&entry);
+            }
+        }
+        else
+        {
+            messages::resourceNotFound(
+                res, "#MessageRegistryFile.v1_1_0.MessageRegistryFile",
+                registry);
+            res.end();
+            return;
+        }
+
+        if (registry != registry1)
+        {
+            messages::resourceNotFound(res, header->type, registry1);
+            res.end();
+            return;
+        }
+
+        res.jsonValue = {{"@Redfish.Copyright", header->copyright},
+                         {"@odata.type", header->type},
+                         {"Id", header->id},
+                         {"Name", header->name},
+                         {"Language", header->language},
+                         {"Description", header->description},
+                         {"RegistryPrefix", header->registryPrefix},
+                         {"RegistryVersion", header->registryVersion},
+                         {"OwningEntity", header->owningEntity}};
 
         nlohmann::json &messageObj = res.jsonValue["Messages"];
 
         // Go through the Message Registry and populate each Message
-        for (const message_registries::MessageEntry &message :
-             message_registries::base::registry)
+        for (const message_registries::MessageEntry *message : registryEntries)
         {
-            nlohmann::json &obj = messageObj[message.first];
-            obj = {{"Description", message.second.description},
-                   {"Message", message.second.message},
-                   {"Severity", message.second.severity},
-                   {"NumberOfArgs", message.second.numberOfArgs},
-                   {"Resolution", message.second.resolution}};
-            if (message.second.numberOfArgs > 0)
+            nlohmann::json &obj = messageObj[message->first];
+            obj = {{"Description", message->second.description},
+                   {"Message", message->second.message},
+                   {"Severity", message->second.severity},
+                   {"NumberOfArgs", message->second.numberOfArgs},
+                   {"Resolution", message->second.resolution}};
+            if (message->second.numberOfArgs > 0)
             {
                 nlohmann::json &messageParamArray = obj["ParamTypes"];
-                for (const char *str : message.second.paramTypes)
+                for (const char *str : message->second.paramTypes)
                 {
                     if (str == nullptr)
                     {
@@ -164,100 +261,4 @@
     }
 };
 
-class OpenBMCMessageRegistryFile : public Node
-{
-  public:
-    template <typename CrowApp>
-    OpenBMCMessageRegistryFile(CrowApp &app) :
-        Node(app, "/redfish/v1/Registries/OpenBMC/")
-    {
-        entityPrivileges = {
-            {boost::beast::http::verb::get, {{"Login"}}},
-            {boost::beast::http::verb::head, {{"Login"}}},
-            {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
-            {boost::beast::http::verb::put, {{"ConfigureManager"}}},
-            {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
-            {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
-    }
-
-  private:
-    void doGet(crow::Response &res, const crow::Request &req,
-               const std::vector<std::string> &params) override
-    {
-        res.jsonValue = {
-            {"@odata.id", "/redfish/v1/Registries/OpenBMC"},
-            {"@odata.type", "#MessageRegistryFile.v1_1_0.MessageRegistryFile"},
-            {"Name", "Open BMC Message Registry File"},
-            {"Description", "Open BMC Message Registry File Location"},
-            {"Id", message_registries::openbmc::header.registryPrefix},
-            {"Registry", message_registries::openbmc::header.id},
-            {"Languages", {"en"}},
-            {"Languages@odata.count", 1},
-            {"Location",
-             {{{"Language", "en"},
-               {"Uri", "/redfish/v1/Registries/OpenBMC/OpenBMC"}}}},
-            {"Location@odata.count", 1}};
-
-        res.end();
-    }
-};
-
-class OpenBMCMessageRegistry : public Node
-{
-  public:
-    template <typename CrowApp>
-    OpenBMCMessageRegistry(CrowApp &app) :
-        Node(app, "/redfish/v1/Registries/OpenBMC/OpenBMC/")
-    {
-        entityPrivileges = {
-            {boost::beast::http::verb::get, {{"Login"}}},
-            {boost::beast::http::verb::head, {{"Login"}}},
-            {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
-            {boost::beast::http::verb::put, {{"ConfigureManager"}}},
-            {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
-            {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
-    }
-
-  private:
-    void doGet(crow::Response &res, const crow::Request &req,
-               const std::vector<std::string> &params) override
-    {
-        res.jsonValue = {
-            {"@Redfish.Copyright",
-             message_registries::openbmc::header.copyright},
-            {"@odata.type", message_registries::openbmc::header.type},
-            {"Id", message_registries::openbmc::header.id},
-            {"Name", message_registries::openbmc::header.name},
-            {"Language", message_registries::openbmc::header.language},
-            {"Description", message_registries::openbmc::header.description},
-            {"RegistryPrefix",
-             message_registries::openbmc::header.registryPrefix},
-            {"RegistryVersion",
-             message_registries::openbmc::header.registryVersion},
-            {"OwningEntity", message_registries::openbmc::header.owningEntity}};
-
-        nlohmann::json &messageObj = res.jsonValue["Messages"];
-        // Go through the Message Registry and populate each Message
-        for (const message_registries::MessageEntry &message :
-             message_registries::openbmc::registry)
-        {
-            nlohmann::json &obj = messageObj[message.first];
-            obj = {{"Description", message.second.description},
-                   {"Message", message.second.message},
-                   {"Severity", message.second.severity},
-                   {"NumberOfArgs", message.second.numberOfArgs},
-                   {"Resolution", message.second.resolution}};
-            if (message.second.numberOfArgs > 0)
-            {
-                nlohmann::json &messageParamArray = obj["ParamTypes"];
-                for (size_t i = 0; i < message.second.numberOfArgs; i++)
-                {
-                    messageParamArray.push_back(message.second.paramTypes[i]);
-                }
-            }
-        }
-        res.end();
-    }
-};
-
 } // namespace redfish
diff --git a/scripts/parse_registries.py b/scripts/parse_registries.py
old mode 100644
new mode 100755
index d5e83bc..df72fd9
--- a/scripts/parse_registries.py
+++ b/scripts/parse_registries.py
@@ -14,7 +14,7 @@
 import xml.etree.ElementTree as ET
 
 REGISTRY_HEADER = '''/*
-// Copyright (c) 2019 Intel Corporation
+// Copyright (c) 2020 Intel Corporation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -53,17 +53,24 @@
     'https': os.environ.get("https_proxy", None)
 }
 
-base_file = requests.get(
-    'https://redfish.dmtf.org/registries/Base.1.4.0.json',
-    proxies=proxies)
-base_file.raise_for_status()
-base_json = json.loads(base_file.text)
-base_path = os.path.join(include_path, "base_message_registry.hpp")
 
-files = [(base_path, base_json, "base")]
+def make_getter(dmtf_name, header_name, type_name):
+    url = 'https://redfish.dmtf.org/registries/{}'.format(dmtf_name)
+    dmtf = requests.get(url, proxies=proxies)
+    dmtf.raise_for_status()
+    json_file = json.loads(dmtf.text)
+    path = os.path.join(include_path, header_name)
+    return (path, json_file, type_name, url)
+
+
+files = []
+files.append(make_getter('Base.1.4.0.json',
+                         'base_message_registry.hpp', 'base'))
+files.append(make_getter('TaskEvent.1.0.1.json',
+                         'task_event_message_registry.hpp', 'task_event'))
 
 # Remove the old files
-for file, json, namespace in files:
+for file, json, namespace, url in files:
     try:
         os.remove(file)
     except BaseException:
@@ -84,6 +91,7 @@
         registry.write("\"{}\",".format(json["OwningEntity"]))
         registry.write("};")
 
+        registry.write('constexpr const char * url = "{}";\n\n'.format(url))
         # Parse each Message entry
         registry.write("constexpr std::array<MessageEntry, {}> registry = {{".format(
             len(json["Messages"])))