MINIFICPP-1116 - Fix error reporting in C2Agent

- Missing CoapProtocol will now result in a fatal error (exception)
instead of segfault. Error reporting is improved.
- C2Agent::protocol_ is now properly deleted
- remove dead code
- avoid unnecessary string copies in loop

Signed-off-by: Arpad Boda <aboda@apache.org>

This closes #706
diff --git a/libminifi/include/c2/C2Agent.h b/libminifi/include/c2/C2Agent.h
index c3945fb..f84c131 100644
--- a/libminifi/include/c2/C2Agent.h
+++ b/libminifi/include/c2/C2Agent.h
@@ -57,7 +57,8 @@
 
   C2Agent(const std::shared_ptr<core::controller::ControllerServiceProvider> &controller, const std::shared_ptr<state::StateMonitor> &updateSink, const std::shared_ptr<Configure> &configure);
 
-  virtual ~C2Agent() {
+  virtual ~C2Agent() noexcept {
+    delete protocol_.load();
   }
 
   /**
diff --git a/libminifi/src/c2/C2Agent.cpp b/libminifi/src/c2/C2Agent.cpp
index 544e752..7c4b6c2 100644
--- a/libminifi/src/c2/C2Agent.cpp
+++ b/libminifi/src/c2/C2Agent.cpp
@@ -40,12 +40,13 @@
 
 C2Agent::C2Agent(const std::shared_ptr<core::controller::ControllerServiceProvider> &controller, const std::shared_ptr<state::StateMonitor> &updateSink,
                  const std::shared_ptr<Configure> &configuration)
-    : controller_(controller),
+    : heart_beat_period_(3000),
+      max_c2_responses(5),
       update_sink_(updateSink),
       update_service_(nullptr),
+      controller_(controller),
       configuration_(configuration),
-      heart_beat_period_(3000),
-      max_c2_responses(5),
+      protocol_(nullptr),
       logger_(logging::LoggerFactory<C2Agent>::getLogger()) {
   allow_updates_ = true;
 
@@ -154,25 +155,24 @@
       clazz = "CoapProtocol";
     }
     logger_->log_info("Class is %s", clazz);
-    auto protocol = core::ClassLoader::getDefaultClassLoader().instantiateRaw(clazz, clazz);
 
+    auto protocol = core::ClassLoader::getDefaultClassLoader().instantiateRaw(clazz, clazz);
     if (protocol == nullptr) {
-      logger_->log_info("Class %s not found", clazz);
+      logger_->log_warn("Class %s not found", clazz);
       protocol = core::ClassLoader::getDefaultClassLoader().instantiateRaw("CoapProtocol", "CoapProtocol");
       if (!protocol) {
-        logger_->log_info("Attempted to load CoapProtocol. To enable C2, please specify an active protocol for this agent.");
-        return;
-      } else {
-        logger_->log_info("Class is CoapProtocol");
+        const char* errmsg = "Attempted to load CoapProtocol. To enable C2, please specify an active protocol for this agent.";
+        logger_->log_error(errmsg);
+        throw minifi::Exception{ minifi::GENERAL_EXCEPTION, errmsg };
       }
+
+      logger_->log_info("Class is CoapProtocol");
     }
-    C2Protocol *old_protocol = protocol_.exchange(dynamic_cast<C2Protocol*>(protocol));
+
+    // Since !reconfigure, the call comes from the ctor and protocol_ is null, therefore no delete is necessary
+    protocol_.exchange(dynamic_cast<C2Protocol *>(protocol));
 
     protocol_.load()->initialize(controller_, configuration_);
-
-    if (reconfigure && old_protocol != nullptr) {
-      delete old_protocol;
-    }
   } else {
     protocol_.load()->update(configure);
   }
@@ -232,7 +232,7 @@
   if (configure->get("nifi.c2.agent.heartbeat.reporter.classes", "c2.agent.heartbeat.reporter.classes", heartbeat_reporters)) {
     std::vector<std::string> reporters = utils::StringUtils::split(heartbeat_reporters, ",");
     std::lock_guard<std::mutex> lock(heartbeat_mutex);
-    for (auto reporter : reporters) {
+    for (const auto& reporter : reporters) {
       auto heartbeat_reporter_obj = core::ClassLoader::getDefaultClassLoader().instantiate(reporter, reporter);
       if (heartbeat_reporter_obj == nullptr) {
         logger_->log_debug("Could not instantiate %s", reporter);
@@ -248,7 +248,7 @@
   if (configure->get("nifi.c2.agent.trigger.classes", "c2.agent.trigger.classes", trigger_classes)) {
     std::vector<std::string> triggers = utils::StringUtils::split(trigger_classes, ",");
     std::lock_guard<std::mutex> lock(heartbeat_mutex);
-    for (auto trigger : triggers) {
+    for (const auto& trigger : triggers) {
       auto trigger_obj = core::ClassLoader::getDefaultClassLoader().instantiate(trigger, trigger);
       if (trigger_obj == nullptr) {
         logger_->log_debug("Could not instantiate %s", trigger);