MINIFICPP-1041: Update JSON header for the connection queues

This closes #652.

Signed-off-by: Aldrin Piri <aldrin@apache.org>
diff --git a/libminifi/include/c2/protocols/RESTProtocol.h b/libminifi/include/c2/protocols/RESTProtocol.h
index 6d848ec..d54e8f0 100644
--- a/libminifi/include/c2/protocols/RESTProtocol.h
+++ b/libminifi/include/c2/protocols/RESTProtocol.h
@@ -18,11 +18,8 @@
 #ifndef LIBMINIFI_INCLUDE_C2_PROTOCOLS_RESTPROTOCOL_H_
 #define LIBMINIFI_INCLUDE_C2_PROTOCOLS_RESTPROTOCOL_H_
 
-
-
 #include <stdexcept>
 
-
 #ifdef RAPIDJSON_ASSERT
 #undef RAPIDJSON_ASSERT
 #endif
@@ -58,7 +55,7 @@
  *
  */
 
-struct ValueObject{
+struct ValueObject {
   std::string name;
   std::vector<rapidjson::Value*> values;
 };
@@ -80,6 +77,12 @@
 
   virtual rapidjson::Value serializeJsonPayload(const C2Payload &payload, rapidjson::Document::AllocatorType &alloc);
 
+  /**
+   * connection queues should have the uuid as the object name; however since we have an internal AST and don't want to
+   * impact backwards copmatibility ( where the object root is the name ), then we should serialize the queues differently.
+   */
+  virtual rapidjson::Value serializeConnectionQueues(const C2Payload &payload, std::string &label, rapidjson::Document::AllocatorType &alloc);
+
   virtual std::string serializeJsonRootPayload(const C2Payload& payload);
 
   virtual void mergePayloadContent(rapidjson::Value &target, const C2Payload &payload, rapidjson::Document::AllocatorType &alloc);
diff --git a/libminifi/src/c2/protocols/RESTProtocol.cpp b/libminifi/src/c2/protocols/RESTProtocol.cpp
index fad4d67..37a53e6 100644
--- a/libminifi/src/c2/protocols/RESTProtocol.cpp
+++ b/libminifi/src/c2/protocols/RESTProtocol.cpp
@@ -311,19 +311,52 @@
   return false;
 }
 
+rapidjson::Value RESTProtocol::serializeConnectionQueues(const C2Payload &payload, std::string &label, rapidjson::Document::AllocatorType &alloc) {
+  rapidjson::Value json_payload(payload.isContainer() ? rapidjson::kArrayType : rapidjson::kObjectType);
+
+  C2Payload adjusted(payload.getOperation(), payload.getIdentifier(), false, payload.isRaw());
+
+  auto name = payload.getLabel();
+  std::string uuid;
+  C2ContentResponse updatedContent(payload.getOperation());
+  for (const C2ContentResponse &content : payload.getContent()) {
+    for (const auto& op_arg : content.operation_arguments) {
+      if (op_arg.first == "uuid") {
+        uuid = op_arg.second.to_string();
+      }
+      updatedContent.operation_arguments.insert(op_arg);
+    }
+  }
+  updatedContent.name = uuid;
+  adjusted.setLabel(uuid);
+  adjusted.setIdentifier(uuid);
+  state::response::ValueNode nd;
+  // name should be what was previously the TLN ( top level node )
+  nd = name;
+  updatedContent.operation_arguments.insert(std::make_pair("name", nd));
+  // the rvalue reference is an unfortunate side effect of the underlying API decision.
+  adjusted.addContent(std::move(updatedContent), true);
+  mergePayloadContent(json_payload, adjusted, alloc);
+  label = uuid;
+  return json_payload;
+}
+
 rapidjson::Value RESTProtocol::serializeJsonPayload(const C2Payload &payload, rapidjson::Document::AllocatorType &alloc) {
-// get the name from the content
+  // get the name from the content
   rapidjson::Value json_payload(payload.isContainer() ? rapidjson::kArrayType : rapidjson::kObjectType);
 
   std::vector<ValueObject> children;
 
+  bool isQueue = payload.getLabel() == "queues";
+
   for (const auto &nested_payload : payload.getNestedPayloads()) {
-    rapidjson::Value* child_payload = new rapidjson::Value(serializeJsonPayload(nested_payload, alloc));
+    std::string label = nested_payload.getLabel();
+    rapidjson::Value* child_payload = new rapidjson::Value(isQueue ? serializeConnectionQueues(nested_payload, label, alloc) : serializeJsonPayload(nested_payload, alloc));
 
     if (nested_payload.isCollapsible()) {
       bool combine = false;
       for (auto &subordinate : children) {
-        if (subordinate.name == nested_payload.getLabel()) {
+        if (subordinate.name == label) {
           subordinate.values.push_back(child_payload);
           combine = true;
           break;
@@ -331,13 +364,13 @@
       }
       if (!combine) {
         ValueObject obj;
-        obj.name = nested_payload.getLabel();
+        obj.name = label;
         obj.values.push_back(child_payload);
         children.push_back(obj);
       }
     } else {
       ValueObject obj;
-      obj.name = nested_payload.getLabel();
+      obj.name = label;
       obj.values.push_back(child_payload);
       children.push_back(obj);
     }