This is an automated email from the ASF dual-hosted git repository.

fgerlits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit e3474f98ec85322b4a362acde178f9491b2c4c0f
Author: Martin Zink <[email protected]>
AuthorDate: Tue Aug 5 18:52:07 2025 +0200

    MINIFICPP-2598 Fixing inherited ControllerService manifest issues
    
    * Renamed SSLContextServiceImpl -> SSLContextService
    * Added ControllerServiceApiDefinition
    * Manifest now includes providedApiImplementations
    * JsonRecordSetWriter now advertises that it implements RecordSetWriter
    * JsonTreeReader now advertises that it implements RecordSetReader
    * SSLContextService now advertises that it implements 
SSLContextServiceInterface
    
    Signed-off-by: Ferenc Gerlits <[email protected]>
    Closes #2001
---
 controller/MiNiFiController.cpp                    |  25 ++--
 controller/tests/ControllerTests.cpp               |   8 +-
 ...ntextService.h => SSLContextServiceInterface.h} |   2 +-
 extension-utils/src/utils/net/Ssl.cpp              |   6 +-
 extensions/civetweb/tests/ListenHTTPTests.cpp      |   6 +-
 .../controllerservices/CouchbaseClusterService.cpp |   8 +-
 .../controllerservices/CouchbaseClusterService.h   |   6 +-
 extensions/elasticsearch/PostElasticsearch.cpp     |   4 +-
 extensions/elasticsearch/PostElasticsearch.h       |   4 +-
 extensions/grafana-loki/PushGrafanaLoki.cpp        |   6 +-
 extensions/grafana-loki/PushGrafanaLoki.h          |   6 +-
 extensions/kafka/KafkaProcessorBase.cpp            |   2 +-
 extensions/kafka/KafkaProcessorBase.h              |   4 +-
 extensions/kafka/PublishKafka.h                    |   4 +-
 extensions/opc/include/fetchopc.h                  |   2 +-
 extensions/opc/include/putopc.h                    |   2 +-
 extensions/prometheus/PrometheusExposerWrapper.h   |   4 +-
 extensions/python/ExecutePythonProcessor.cpp       |   4 +-
 extensions/python/types/PyProcessContext.cpp       |   2 +-
 extensions/python/types/PySSLContextService.h      |   4 +-
 extensions/sftp/processors/PutSFTP.h               |   2 +-
 extensions/sftp/processors/SFTPProcessorBase.h     |   2 +-
 extensions/splunk/PutSplunkHTTP.h                  |   2 +-
 extensions/splunk/SplunkHECProcessor.cpp           |   6 +-
 extensions/splunk/SplunkHECProcessor.h             |  10 +-
 .../controllers/JsonRecordSetWriter.h              |   1 +
 .../controllers/JsonTreeReader.h                   |   1 +
 .../standard-processors/modbus/FetchModbusTcp.cpp  |   2 +-
 .../standard-processors/modbus/FetchModbusTcp.h    |   4 +-
 .../standard-processors/processors/GetTCP.cpp      |   2 +-
 extensions/standard-processors/processors/GetTCP.h |   4 +-
 .../standard-processors/processors/InvokeHTTP.cpp  |   2 +-
 .../standard-processors/processors/InvokeHTTP.h    |   6 +-
 .../processors/ListenSyslog.cpp                    |   3 +-
 .../standard-processors/processors/ListenSyslog.h  |   4 +-
 .../standard-processors/processors/ListenTCP.cpp   |   4 +-
 .../standard-processors/processors/ListenTCP.h     |   8 +-
 .../standard-processors/processors/ListenUDP.cpp   |   2 +-
 .../standard-processors/processors/PutTCP.cpp      |   2 +-
 extensions/standard-processors/processors/PutTCP.h |  20 +--
 .../tests/integration/VerifyInvokeHTTP.h           |   2 +-
 .../standard-processors/tests/unit/GetTCPTests.cpp |   6 +-
 .../tests/unit/ListenSyslogTests.cpp               |   6 +-
 .../tests/unit/ListenTcpTests.cpp                  |  16 +--
 .../tests/unit/ManifestTests.cpp                   | 152 +++++++++++++++++++++
 .../standard-processors/tests/unit/PutTCPTests.cpp |   8 +-
 libminifi/include/RemoteProcessorGroupPort.h       |   4 +-
 libminifi/include/c2/ControllerSocketProtocol.h    |   6 +-
 libminifi/include/c2/protocols/RESTSender.h        |   4 +-
 .../controllers/NetworkPrioritizerService.h        |   1 -
 libminifi/include/controllers/SSLContextService.h  |  32 +++--
 libminifi/include/core/logging/alert/AlertSink.h   |   4 +-
 libminifi/include/sitetosite/SiteToSite.h          |   8 +-
 libminifi/include/sitetosite/SiteToSiteClient.h    |   4 +-
 libminifi/src/RemoteProcessorGroupPort.cpp         |  22 ++-
 libminifi/src/c2/ControllerSocketProtocol.cpp      |  27 ++--
 libminifi/src/c2/protocols/RESTSender.cpp          |   6 +-
 libminifi/src/controllers/SSLContextService.cpp    |  40 +++---
 libminifi/src/core/logging/alert/AlertSink.cpp     |   4 +-
 .../src/core/state/nodes/AgentInformation.cpp      |  13 +-
 .../ControllerServiceIntegrationTests.cpp          |  16 +--
 libminifi/test/integration/HTTPSiteToSiteTests.cpp |   2 +-
 libminifi/test/integration/SiteToSiteRestTest.cpp  |  15 +-
 .../integration/TimeoutHTTPSiteToSiteTests.cpp     |   2 +-
 libminifi/test/unit/NetUtilsTest.cpp               |  58 ++++----
 minifi-api/include/minifi-cpp/agent/agent_docs.h   |   2 +
 .../minifi-cpp/controllers/RecordSetReader.h       |   6 +
 .../minifi-cpp/controllers/RecordSetWriter.h       |   7 +
 ...ntextService.h => SSLContextServiceInterface.h} |  10 +-
 .../core/ControllerServiceApiDefinition.h          |  14 +-
 utils/include/agent/agent_docs.h                   |   3 +-
 utils/include/core/controller/ControllerService.h  |   4 +
 utils/include/http/BaseHTTPClient.h                |   6 +-
 utils/include/http/HTTPClient.h                    |  15 +-
 utils/include/utils/net/AsioSocketUtils.h          |  21 ++-
 utils/src/http/HTTPClient.cpp                      |   4 +-
 utils/src/utils/net/AsioSocketUtils.cpp            |   6 +-
 77 files changed, 478 insertions(+), 274 deletions(-)

diff --git a/controller/MiNiFiController.cpp b/controller/MiNiFiController.cpp
index 33be0ed71..2c1f7a356 100644
--- a/controller/MiNiFiController.cpp
+++ b/controller/MiNiFiController.cpp
@@ -15,23 +15,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <vector>
+#include <filesystem>
 #include <iostream>
 #include <string>
 #include <string_view>
-#include <filesystem>
+#include <vector>
 
-#include "MainHelper.h"
-#include "properties/Configure.h"
 #include "Controller.h"
+#include "Exception.h"
+#include "MainHelper.h"
+#include "agent/agent_version.h"
+#include "argparse/argparse.hpp"
 #include "c2/ControllerSocketProtocol.h"
+#include "controllers/SSLContextService.h"
+#include "core/ConfigurationFactory.h"
 #include "core/controller/ControllerService.h"
 #include "core/extension/ExtensionManager.h"
-#include "core/ConfigurationFactory.h"
-#include "Exception.h"
-#include "argparse/argparse.hpp"
+#include "properties/Configure.h"
 #include "range/v3/algorithm/contains.hpp"
-#include "agent/agent_version.h"
 
 namespace minifi = org::apache::nifi::minifi;
 
@@ -61,14 +62,14 @@ 
std::shared_ptr<minifi::core::controller::ControllerService> getControllerServic
   return controller->getControllerServiceImplementation();
 }
 
-std::shared_ptr<minifi::controllers::SSLContextService> 
getSSLContextService(const std::shared_ptr<minifi::Configure>& configuration) {
-  std::shared_ptr<minifi::controllers::SSLContextService> secure_context;
+std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
getSSLContextService(const std::shared_ptr<minifi::Configure>& configuration) {
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
secure_context;
   std::string context_name;
   // if the user wishes to use a controller service we need to instantiate the 
flow
   if (configuration->get(minifi::Configure::controller_ssl_context_service, 
context_name) && !context_name.empty()) {
     const auto service = getControllerService(configuration, context_name);
     if (nullptr != service) {
-      secure_context = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(service);
+      secure_context = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(service);
     }
     if (secure_context == nullptr) {
       throw minifi::Exception(minifi::GENERAL_EXCEPTION, "SSL Context was set, 
but the context name '" + context_name + "' could not be found");
@@ -78,7 +79,7 @@ std::shared_ptr<minifi::controllers::SSLContextService> 
getSSLContextService(con
   if (nullptr == secure_context) {
     std::string secureStr;
     if (configuration->get(minifi::Configure::nifi_remote_input_secure, 
secureStr) && minifi::utils::string::toBool(secureStr).value_or(false)) {
-      secure_context = 
std::make_shared<minifi::controllers::SSLContextServiceImpl>("ControllerSocketProtocolSSL",
 configuration);
+      secure_context = 
std::make_shared<minifi::controllers::SSLContextService>("ControllerSocketProtocolSSL",
 configuration);
       secure_context->onEnable();
     }
   } else {
diff --git a/controller/tests/ControllerTests.cpp 
b/controller/tests/ControllerTests.cpp
index ab9debb68..21cd74c4b 100644
--- a/controller/tests/ControllerTests.cpp
+++ b/controller/tests/ControllerTests.cpp
@@ -204,7 +204,7 @@ class TestControllerSocketReporter : public 
c2::ControllerSocketReporter {
 
 class TestControllerServiceProvider : public 
core::controller::ControllerServiceProviderImpl {
  public:
-  explicit 
TestControllerServiceProvider(std::shared_ptr<controllers::SSLContextService> 
ssl_context_service)
+  explicit 
TestControllerServiceProvider(std::shared_ptr<controllers::SSLContextServiceInterface>
 ssl_context_service)
     : 
core::controller::ControllerServiceProviderImpl("TestControllerServiceProvider"),
       ssl_context_service_(std::move(ssl_context_service)) {
   }
@@ -228,7 +228,7 @@ class TestControllerServiceProvider : public 
core::controller::ControllerService
 
  private:
   bool is_ssl_{};
-  std::shared_ptr<controllers::SSLContextService> ssl_context_service_;
+  std::shared_ptr<controllers::SSLContextServiceInterface> 
ssl_context_service_;
 };
 
 class ControllerTestFixture {
@@ -250,7 +250,7 @@ class ControllerTestFixture {
     configuration_->set(minifi::Configure::nifi_security_client_pass_phrase, 
"abcdefgh");
     
configuration_->set(minifi::Configure::nifi_security_client_ca_certificate, 
(minifi::utils::file::FileUtils::get_executable_dir() / "resources" / 
"root-ca.pem").string());
     configuration_->set(minifi::Configure::controller_ssl_context_service, 
"SSLContextService");
-    ssl_context_service_ = 
std::make_shared<controllers::SSLContextServiceImpl>("SSLContextService", 
configuration_);
+    ssl_context_service_ = 
std::make_shared<controllers::SSLContextService>("SSLContextService", 
configuration_);
     ssl_context_service_->onEnable();
     controller_service_provider_ = 
std::make_unique<TestControllerServiceProvider>(ssl_context_service_);
     controller_socket_data_.host = "localhost";
@@ -283,7 +283,7 @@ class ControllerTestFixture {
   std::shared_ptr<TestStateController> controller_;
   std::unique_ptr<TestUpdateSink> update_sink_;
   std::unique_ptr<minifi::c2::ControllerSocketProtocol> 
controller_socket_protocol_;
-  std::shared_ptr<controllers::SSLContextService> ssl_context_service_;
+  std::shared_ptr<controllers::SSLContextServiceInterface> 
ssl_context_service_;
   std::unique_ptr<TestControllerServiceProvider> controller_service_provider_;
   minifi::utils::net::SocketData controller_socket_data_;
 };
diff --git a/extension-utils/include/controllers/SSLContextService.h 
b/extension-utils/include/controllers/SSLContextServiceInterface.h
similarity index 92%
copy from extension-utils/include/controllers/SSLContextService.h
copy to extension-utils/include/controllers/SSLContextServiceInterface.h
index e399a734a..0c9c535c2 100644
--- a/extension-utils/include/controllers/SSLContextService.h
+++ b/extension-utils/include/controllers/SSLContextServiceInterface.h
@@ -16,4 +16,4 @@
  */
 #pragma once
 
-#include "minifi-cpp/controllers/SSLContextService.h"
\ No newline at end of file
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
\ No newline at end of file
diff --git a/extension-utils/src/utils/net/Ssl.cpp 
b/extension-utils/src/utils/net/Ssl.cpp
index 4534c4c5f..0f42fa6b0 100644
--- a/extension-utils/src/utils/net/Ssl.cpp
+++ b/extension-utils/src/utils/net/Ssl.cpp
@@ -15,15 +15,15 @@
  * limitations under the License.
  */
 #include "utils/net/Ssl.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 
 namespace org::apache::nifi::minifi::utils::net {
 
 std::optional<utils::net::SslData> getSslData(const core::ProcessContext& 
context, const core::PropertyReference& ssl_prop, const 
std::shared_ptr<core::logging::Logger>& logger) {
-  auto getSslContextService = [&]() -> 
std::shared_ptr<minifi::controllers::SSLContextService> {
+  auto getSslContextService = [&]() -> 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface> {
     if (auto ssl_service_name = context.getProperty(ssl_prop); 
ssl_service_name && !ssl_service_name->empty()) {
       if (auto service = context.getControllerService(*ssl_service_name, 
context.getProcessor().getUUID())) {
-        if (auto ssl_service = 
std::dynamic_pointer_cast<org::apache::nifi::minifi::controllers::SSLContextService>(service))
 {
+        if (auto ssl_service = 
std::dynamic_pointer_cast<org::apache::nifi::minifi::controllers::SSLContextServiceInterface>(service))
 {
           return ssl_service;
         } else {
           logger->log_warn("SSL Context Service property is set to '{}', but 
it is not a valid SSLContextService.", *ssl_service_name);
diff --git a/extensions/civetweb/tests/ListenHTTPTests.cpp 
b/extensions/civetweb/tests/ListenHTTPTests.cpp
index d580d0530..b439886ec 100644
--- a/extensions/civetweb/tests/ListenHTTPTests.cpp
+++ b/extensions/civetweb/tests/ListenHTTPTests.cpp
@@ -69,7 +69,7 @@ class ListenHTTPTestsFixture {
     
LogTestController::getInstance().setTrace<minifi::processors::ListenHTTP::Handler>();
     
LogTestController::getInstance().setDebug<minifi::processors::LogAttribute>();
     LogTestController::getInstance().setDebug<minifi::http::HTTPClient>();
-    
LogTestController::getInstance().setDebug<minifi::controllers::SSLContextService>();
+    
LogTestController::getInstance().setDebug<minifi::controllers::SSLContextServiceInterface>();
 
     // Create temporary directories
     tmp_dir = testController.createTempDirectory();
@@ -135,7 +135,7 @@ class ListenHTTPTestsFixture {
       config->set(minifi::Configure::nifi_security_client_private_key, 
(executable_dir / "resources" / client_cert).string());
       config->set(minifi::Configure::nifi_security_client_pass_phrase, 
"Password12");
     }
-    ssl_context_service = 
std::make_shared<minifi::controllers::SSLContextServiceImpl>("SSLContextService",
 config);
+    ssl_context_service = 
std::make_shared<minifi::controllers::SSLContextService>("SSLContextService", 
config);
     ssl_context_service->onEnable();
   }
 
@@ -259,7 +259,7 @@ class ListenHTTPTestsFixture {
   core::Processor* listen_http = nullptr;
   core::Processor* log_attribute = nullptr;
 
-  std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service;
   HttpRequestMethod method = HttpRequestMethod::GET;
   std::map<std::string, std::string> headers;
   std::string payload;
diff --git 
a/extensions/couchbase/controllerservices/CouchbaseClusterService.cpp 
b/extensions/couchbase/controllerservices/CouchbaseClusterService.cpp
index a86702b98..d8dc2066f 100644
--- a/extensions/couchbase/controllerservices/CouchbaseClusterService.cpp
+++ b/extensions/couchbase/controllerservices/CouchbaseClusterService.cpp
@@ -50,12 +50,12 @@ CouchbaseErrorType getErrorType(const std::error_code& 
error_code) {
 
 }  // namespace
 
-CouchbaseClient::CouchbaseClient(std::string connection_string, std::string 
username, std::string password, minifi::controllers::SSLContextService* 
ssl_context_service,
+CouchbaseClient::CouchbaseClient(std::string connection_string, std::string 
username, std::string password, 
minifi::controllers::SSLContextServiceInterface* ssl_context_service,
   const std::shared_ptr<core::logging::Logger>& logger)
     : connection_string_(std::move(connection_string)), logger_(logger), 
cluster_options_(buildClusterOptions(std::move(username), std::move(password), 
ssl_context_service)) {
 }
 
-::couchbase::cluster_options CouchbaseClient::buildClusterOptions(std::string 
username, std::string password, minifi::controllers::SSLContextService* 
ssl_context_service) {
+::couchbase::cluster_options CouchbaseClient::buildClusterOptions(std::string 
username, std::string password, 
minifi::controllers::SSLContextServiceInterface* ssl_context_service) {
   if (username.empty() && (!ssl_context_service || (ssl_context_service && 
ssl_context_service->getCertificateFile().empty()))) {
     throw minifi::Exception(ExceptionType::PROCESS_SCHEDULE_EXCEPTION, 
"Neither username and password nor SSLContextService is provided for Couchbase 
authentication");
   }
@@ -228,9 +228,9 @@ void CouchbaseClusterService::onEnable() {
     throw minifi::Exception(ExceptionType::PROCESS_SCHEDULE_EXCEPTION, 
"Missing username and password or SSLContextService as a linked service");
   }
 
-  minifi::controllers::SSLContextService* ssl_context_service_ptr = nullptr;
+  minifi::controllers::SSLContextServiceInterface* ssl_context_service_ptr = 
nullptr;
   if (!linked_services_.empty()) {
-    auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(linked_services_[0]);
+    auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(linked_services_[0]);
     if (!ssl_context_service) {
       throw minifi::Exception(ExceptionType::PROCESS_SCHEDULE_EXCEPTION, 
"Linked service is not an SSLContextService");
     }
diff --git a/extensions/couchbase/controllerservices/CouchbaseClusterService.h 
b/extensions/couchbase/controllerservices/CouchbaseClusterService.h
index 0da173c91..040b6773f 100644
--- a/extensions/couchbase/controllerservices/CouchbaseClusterService.h
+++ b/extensions/couchbase/controllerservices/CouchbaseClusterService.h
@@ -31,7 +31,7 @@
 #include "couchbase/cluster.hxx"
 #include "core/ProcessContext.h"
 #include "core/logging/LoggerFactory.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 
 namespace org::apache::nifi::minifi::couchbase {
 
@@ -70,7 +70,7 @@ enum class CouchbaseErrorType {
 
 class CouchbaseClient {
  public:
-  CouchbaseClient(std::string connection_string, std::string username, 
std::string password, controllers::SSLContextService* ssl_context_service,
+  CouchbaseClient(std::string connection_string, std::string username, 
std::string password, controllers::SSLContextServiceInterface* 
ssl_context_service,
     const std::shared_ptr<core::logging::Logger>& logger);
 
   ~CouchbaseClient() {
@@ -89,7 +89,7 @@ class CouchbaseClient {
   void close();
 
  private:
-  ::couchbase::cluster_options buildClusterOptions(std::string username, 
std::string password, minifi::controllers::SSLContextService* 
ssl_context_service);
+  ::couchbase::cluster_options buildClusterOptions(std::string username, 
std::string password, minifi::controllers::SSLContextServiceInterface* 
ssl_context_service);
   nonstd::expected<::couchbase::collection, CouchbaseErrorType> 
getCollection(const CouchbaseCollection& collection);
 
   std::string connection_string_;
diff --git a/extensions/elasticsearch/PostElasticsearch.cpp 
b/extensions/elasticsearch/PostElasticsearch.cpp
index c68190f06..05e0835e6 100644
--- a/extensions/elasticsearch/PostElasticsearch.cpp
+++ b/extensions/elasticsearch/PostElasticsearch.cpp
@@ -39,8 +39,8 @@ void PostElasticsearch::initialize() {
 
 auto PostElasticsearch::getSSLContextService(core::ProcessContext& context) 
const {
   if (auto ssl_context = context.getProperty(PostElasticsearch::SSLContext))
-    return 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(context.getControllerService(*ssl_context,
 getUUID()));
-  return std::shared_ptr<minifi::controllers::SSLContextService>{};
+    return 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(context.getControllerService(*ssl_context,
 getUUID()));
+  return std::shared_ptr<minifi::controllers::SSLContextServiceInterface>{};
 }
 
 auto PostElasticsearch::getCredentialsService(core::ProcessContext& context) 
const {
diff --git a/extensions/elasticsearch/PostElasticsearch.h 
b/extensions/elasticsearch/PostElasticsearch.h
index 1ea1e51f7..6f92d8799 100644
--- a/extensions/elasticsearch/PostElasticsearch.h
+++ b/extensions/elasticsearch/PostElasticsearch.h
@@ -22,7 +22,7 @@
 #include <memory>
 #include <vector>
 
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "ElasticsearchCredentialsControllerService.h"
 #include "core/Processor.h"
 #include "core/PropertyDefinition.h"
@@ -63,7 +63,7 @@ class PostElasticsearch : public core::ProcessorImpl {
       .withDescription("The SSL Context Service used to provide client 
certificate "
           "information for TLS/SSL (https) connections.")
       .isRequired(false)
-      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
       .build();
   EXTENSIONAPI static constexpr auto Hosts = 
core::PropertyDefinitionBuilder<>::createProperty("Hosts")
       .withDescription("A comma-separated list of HTTP hosts that host 
Elasticsearch query nodes. Currently only supports a single host.")
diff --git a/extensions/grafana-loki/PushGrafanaLoki.cpp 
b/extensions/grafana-loki/PushGrafanaLoki.cpp
index d37bff95c..29eba22d5 100644
--- a/extensions/grafana-loki/PushGrafanaLoki.cpp
+++ b/extensions/grafana-loki/PushGrafanaLoki.cpp
@@ -77,11 +77,11 @@ void 
PushGrafanaLoki::LogBatch::setStartPushTime(std::chrono::system_clock::time
 
 const core::Relationship PushGrafanaLoki::Self("__self__", "Marks the FlowFile 
to be owned by this processor");
 
-std::shared_ptr<minifi::controllers::SSLContextService> 
PushGrafanaLoki::getSSLContextService(core::ProcessContext& context) const {
+std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
PushGrafanaLoki::getSSLContextService(core::ProcessContext& context) const {
   if (auto ssl_context = 
context.getProperty(PushGrafanaLoki::SSLContextService)) {
-    return 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(context.getControllerService(*ssl_context,
 getUUID()));
+    return 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(context.getControllerService(*ssl_context,
 getUUID()));
   }
-  return std::shared_ptr<minifi::controllers::SSLContextService>{};
+  return std::shared_ptr<minifi::controllers::SSLContextServiceInterface>{};
 }
 
 void PushGrafanaLoki::setUpStateManager(core::ProcessContext& context) {
diff --git a/extensions/grafana-loki/PushGrafanaLoki.h 
b/extensions/grafana-loki/PushGrafanaLoki.h
index b8307d80b..d33569058 100644
--- a/extensions/grafana-loki/PushGrafanaLoki.h
+++ b/extensions/grafana-loki/PushGrafanaLoki.h
@@ -21,7 +21,7 @@
 #include <vector>
 #include <map>
 
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Processor.h"
 #include "core/PropertyDefinition.h"
 #include "core/PropertyDefinitionBuilder.h"
@@ -79,7 +79,7 @@ class PushGrafanaLoki : public core::ProcessorImpl {
     .build();
   EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
     .withDescription("The SSL Context Service used to provide client 
certificate information for TLS/SSL (https) connections.")
-    .withAllowedTypes<minifi::controllers::SSLContextService>()
+    .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
     .build();
   EXTENSIONAPI static constexpr auto Properties = 
utils::array_cat(std::to_array<core::PropertyReference>({
       Url,
@@ -135,7 +135,7 @@ class PushGrafanaLoki : public core::ProcessorImpl {
 
   static std::map<std::string, std::string> 
buildStreamLabelMap(core::ProcessContext& context);
 
-  std::shared_ptr<minifi::controllers::SSLContextService> 
getSSLContextService(core::ProcessContext& context) const;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
getSSLContextService(core::ProcessContext& context) const;
   void processBatch(const std::vector<std::shared_ptr<core::FlowFile>>& 
batched_flow_files, core::ProcessSession& session);
   virtual nonstd::expected<void, std::string> submitRequest(const 
std::vector<std::shared_ptr<core::FlowFile>>& batched_flow_files, 
core::ProcessSession& session) = 0;
   void initializeHttpClient(core::ProcessContext& context);
diff --git a/extensions/kafka/KafkaProcessorBase.cpp 
b/extensions/kafka/KafkaProcessorBase.cpp
index e4de864f1..f864bd278 100644
--- a/extensions/kafka/KafkaProcessorBase.cpp
+++ b/extensions/kafka/KafkaProcessorBase.cpp
@@ -16,7 +16,7 @@
  */
 #include "KafkaProcessorBase.h"
 
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "rdkafka_utils.h"
 #include "utils/ProcessorConfigUtils.h"
 
diff --git a/extensions/kafka/KafkaProcessorBase.h 
b/extensions/kafka/KafkaProcessorBase.h
index fa0c05a33..1d6a44c7c 100644
--- a/extensions/kafka/KafkaProcessorBase.h
+++ b/extensions/kafka/KafkaProcessorBase.h
@@ -20,7 +20,7 @@
 #include <optional>
 #include <string_view>
 
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Processor.h"
 #include "core/PropertyDefinitionBuilder.h"
 #include "rdkafka_utils.h"
@@ -40,7 +40,7 @@ class KafkaProcessorBase : public core::ProcessorImpl {
   EXTENSIONAPI static constexpr auto SSLContextService =
       core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
           .withDescription("SSL Context Service Name")
-          .withAllowedTypes<minifi::controllers::SSLContextService>()
+          .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
           .build();
   EXTENSIONAPI static constexpr auto SecurityProtocol =
       
core::PropertyDefinitionBuilder<magic_enum::enum_count<kafka::SecurityProtocolOption>()>::createProperty(
diff --git a/extensions/kafka/PublishKafka.h b/extensions/kafka/PublishKafka.h
index aa3542b4d..01f0bfef8 100644
--- a/extensions/kafka/PublishKafka.h
+++ b/extensions/kafka/PublishKafka.h
@@ -29,16 +29,16 @@
 
 #include "KafkaConnection.h"
 #include "KafkaProcessorBase.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Core.h"
 #include "core/FlowFile.h"
 #include "core/ProcessSession.h"
 #include "core/PropertyDefinition.h"
 #include "core/PropertyDefinitionBuilder.h"
-#include "minifi-cpp/core/PropertyValidator.h"
 #include "core/RelationshipDefinition.h"
 #include "core/logging/Logger.h"
 #include "core/logging/LoggerFactory.h"
+#include "minifi-cpp/core/PropertyValidator.h"
 #include "rdkafka.h"
 #include "utils/ArrayUtils.h"
 #include "utils/RegexUtils.h"
diff --git a/extensions/opc/include/fetchopc.h 
b/extensions/opc/include/fetchopc.h
index ada1522f8..0017a73f0 100644
--- a/extensions/opc/include/fetchopc.h
+++ b/extensions/opc/include/fetchopc.h
@@ -31,7 +31,7 @@
 #include "core/PropertyDefinitionBuilder.h"
 #include "minifi-cpp/core/PropertyValidator.h"
 #include "core/RelationshipDefinition.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/logging/LoggerFactory.h"
 #include "utils/ArrayUtils.h"
 #include "utils/Id.h"
diff --git a/extensions/opc/include/putopc.h b/extensions/opc/include/putopc.h
index cf29c6e47..c4ecff7e9 100644
--- a/extensions/opc/include/putopc.h
+++ b/extensions/opc/include/putopc.h
@@ -30,7 +30,7 @@
 #include "core/Property.h"
 #include "core/PropertyDefinitionBuilder.h"
 #include "minifi-cpp/core/PropertyValidator.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/logging/LoggerFactory.h"
 #include "utils/ArrayUtils.h"
 #include "utils/Id.h"
diff --git a/extensions/prometheus/PrometheusExposerWrapper.h 
b/extensions/prometheus/PrometheusExposerWrapper.h
index 7d5d157a7..362a854f7 100644
--- a/extensions/prometheus/PrometheusExposerWrapper.h
+++ b/extensions/prometheus/PrometheusExposerWrapper.h
@@ -21,10 +21,10 @@
 #include <vector>
 
 #include "MetricsExposer.h"
-#include "prometheus/exposer.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/logging/Logger.h"
 #include "core/logging/LoggerFactory.h"
-#include "controllers/SSLContextService.h"
+#include "prometheus/exposer.h"
 
 namespace org::apache::nifi::minifi::extensions::prometheus {
 
diff --git a/extensions/python/ExecutePythonProcessor.cpp 
b/extensions/python/ExecutePythonProcessor.cpp
index 836c6583b..83ad37405 100644
--- a/extensions/python/ExecutePythonProcessor.cpp
+++ b/extensions/python/ExecutePythonProcessor.cpp
@@ -22,7 +22,7 @@
 #include <utility>
 
 #include "PythonConfigState.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Resource.h"
 #include "range/v3/algorithm/find_if.hpp"
 #include "range/v3/range/conversion.hpp"
@@ -205,7 +205,7 @@ void ExecutePythonProcessor::addProperty(const std::string 
&name, const std::str
     
builder.withValidator(translateCodeToPropertyValidator(static_cast<PropertyValidatorCode>(*property_type_code)));
   }
   if (controller_service_type_name && *controller_service_type_name == 
"SSLContextService") {
-    builder.withAllowedTypes<controllers::SSLContextService>();
+    builder.withAllowedTypes<controllers::SSLContextServiceInterface>();
   }
   const auto property_definition = builder.build();
 
diff --git a/extensions/python/types/PyProcessContext.cpp 
b/extensions/python/types/PyProcessContext.cpp
index 053b1523f..0d39f6ce7 100644
--- a/extensions/python/types/PyProcessContext.cpp
+++ b/extensions/python/types/PyProcessContext.cpp
@@ -126,7 +126,7 @@ PyObject* 
PyProcessContext::getControllerService(PyProcessContext* self, PyObjec
   if (auto controller_service = 
context->getControllerService(controller_service_name, 
context->getProcessor().getUUID())) {
     std::string controller_service_type_str = controller_service_type;
     if (controller_service_type_str == "SSLContextService") {
-      auto ssl_ctx_service = 
std::dynamic_pointer_cast<controllers::SSLContextService>(controller_service);
+      auto ssl_ctx_service = 
std::dynamic_pointer_cast<controllers::SSLContextServiceInterface>(controller_service);
       return object::returnReference(std::weak_ptr(ssl_ctx_service));
     } else if (controller_service_type_str == "RecordSetReader") {
       auto record_set_reader = 
std::dynamic_pointer_cast<core::RecordSetReader>(controller_service);
diff --git a/extensions/python/types/PySSLContextService.h 
b/extensions/python/types/PySSLContextService.h
index 043096ef1..3fd5e7fec 100644
--- a/extensions/python/types/PySSLContextService.h
+++ b/extensions/python/types/PySSLContextService.h
@@ -18,14 +18,14 @@
 
 #include <memory>
 
-#include "controllers/SSLContextService.h"
 #include "../PythonBindings.h"
+#include "controllers/SSLContextServiceInterface.h"
 
 namespace org::apache::nifi::minifi::extensions::python {
 
 struct PySSLContextService {
   PySSLContextService() {}
-  using HeldType = std::weak_ptr<controllers::SSLContextService>;
+  using HeldType = std::weak_ptr<controllers::SSLContextServiceInterface>;
   static constexpr const char* HeldTypeName = "PySSLContextService::HeldType";
 
   PyObject_HEAD
diff --git a/extensions/sftp/processors/PutSFTP.h 
b/extensions/sftp/processors/PutSFTP.h
index 3acce0dba..87c2ba036 100644
--- a/extensions/sftp/processors/PutSFTP.h
+++ b/extensions/sftp/processors/PutSFTP.h
@@ -34,7 +34,7 @@
 #include "core/PropertyDefinitionBuilder.h"
 #include "minifi-cpp/core/PropertyValidator.h"
 #include "core/RelationshipDefinition.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/logging/LoggerFactory.h"
 #include "utils/ArrayUtils.h"
 #include "utils/Id.h"
diff --git a/extensions/sftp/processors/SFTPProcessorBase.h 
b/extensions/sftp/processors/SFTPProcessorBase.h
index d9e199b2e..f1135f731 100644
--- a/extensions/sftp/processors/SFTPProcessorBase.h
+++ b/extensions/sftp/processors/SFTPProcessorBase.h
@@ -32,7 +32,7 @@
 #include "core/PropertyDefinition.h"
 #include "core/PropertyDefinitionBuilder.h"
 #include "minifi-cpp/core/PropertyValidator.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "utils/Id.h"
 #include "../client/SFTPClient.h"
 
diff --git a/extensions/splunk/PutSplunkHTTP.h 
b/extensions/splunk/PutSplunkHTTP.h
index 831201aeb..1dcc4f392 100644
--- a/extensions/splunk/PutSplunkHTTP.h
+++ b/extensions/splunk/PutSplunkHTTP.h
@@ -110,7 +110,7 @@ class PutSplunkHTTP final : public SplunkHECProcessor {
  private:
   std::string getEndpoint(http::HTTPClient& client);
 
-  std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service_;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service_;
   std::optional<std::string> source_type_;
   std::optional<std::string> source_;
   std::optional<std::string> host_;
diff --git a/extensions/splunk/SplunkHECProcessor.cpp 
b/extensions/splunk/SplunkHECProcessor.cpp
index 88655178e..58ba0827a 100644
--- a/extensions/splunk/SplunkHECProcessor.cpp
+++ b/extensions/splunk/SplunkHECProcessor.cpp
@@ -40,13 +40,13 @@ std::string SplunkHECProcessor::getNetworkLocation() const {
   return hostname_ + ":" + port_;
 }
 
-std::shared_ptr<minifi::controllers::SSLContextService> 
SplunkHECProcessor::getSSLContextService(core::ProcessContext& context) const {
+std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
SplunkHECProcessor::getSSLContextService(core::ProcessContext& context) const {
   if (const auto context_name = context.getProperty(SSLContext); context_name 
&& !IsNullOrEmpty(*context_name))
-    return 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(context.getControllerService(*context_name,
 getUUID()));
+    return 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(context.getControllerService(*context_name,
 getUUID()));
   return nullptr;
 }
 
-void SplunkHECProcessor::initializeClient(http::HTTPClient& client, const 
std::string &url, std::shared_ptr<minifi::controllers::SSLContextService> 
ssl_context_service) const {
+void SplunkHECProcessor::initializeClient(http::HTTPClient& client, const 
std::string &url, 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service) const {
   client.initialize(http::HttpRequestMethod::POST, url, 
std::move(ssl_context_service));
   client.setRequestHeader("Authorization", token_);
   client.setRequestHeader("X-Splunk-Request-Channel", request_channel_);
diff --git a/extensions/splunk/SplunkHECProcessor.h 
b/extensions/splunk/SplunkHECProcessor.h
index 43e95f697..6fc8641b6 100644
--- a/extensions/splunk/SplunkHECProcessor.h
+++ b/extensions/splunk/SplunkHECProcessor.h
@@ -20,13 +20,13 @@
 #include <string>
 #include <utility>
 
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Core.h"
 #include "core/Processor.h"
 #include "core/PropertyDefinition.h"
 #include "core/PropertyDefinitionBuilder.h"
-#include "minifi-cpp/core/PropertyValidator.h"
 #include "http/HTTPClient.h"
+#include "minifi-cpp/core/PropertyValidator.h"
 
 namespace org::apache::nifi::minifi::extensions::curl {
 class HTTPClient;
@@ -59,7 +59,7 @@ class SplunkHECProcessor : public core::ProcessorImpl {
       .withDescription("The SSL Context Service used to provide client 
certificate information for TLS/SSL (https) connections.")
       .isRequired(false)
       .withExclusiveOfProperties({{{"Hostname", "^http:.*$"}}})
-      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
       .build();
   EXTENSIONAPI static constexpr auto Properties = 
std::to_array<core::PropertyReference>({
       Hostname,
@@ -80,8 +80,8 @@ class SplunkHECProcessor : public core::ProcessorImpl {
 
  protected:
   std::string getNetworkLocation() const;
-  std::shared_ptr<minifi::controllers::SSLContextService> 
getSSLContextService(core::ProcessContext& context) const;
-  void initializeClient(http::HTTPClient& client, const std::string &url, 
std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service) 
const;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
getSSLContextService(core::ProcessContext& context) const;
+  void initializeClient(http::HTTPClient& client, const std::string &url, 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service) const;
 
   std::string token_;
   std::string hostname_;
diff --git a/extensions/standard-processors/controllers/JsonRecordSetWriter.h 
b/extensions/standard-processors/controllers/JsonRecordSetWriter.h
index 01e33c872..97553f37b 100644
--- a/extensions/standard-processors/controllers/JsonRecordSetWriter.h
+++ b/extensions/standard-processors/controllers/JsonRecordSetWriter.h
@@ -83,6 +83,7 @@ class JsonRecordSetWriter final : public 
core::RecordSetWriterImpl {
   });
 
   EXTENSIONAPI static constexpr bool SupportsDynamicProperties = false;
+  EXTENSIONAPI static constexpr auto ImplementsApis = std::array{ 
RecordSetWriter::ProvidesApi };
   ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_CONTROLLER_SERVICES
 
   void write(const core::RecordSet& record_set, const 
std::shared_ptr<core::FlowFile>& flow_file, core::ProcessSession& session) 
override;
diff --git a/extensions/standard-processors/controllers/JsonTreeReader.h 
b/extensions/standard-processors/controllers/JsonTreeReader.h
index a57b48bc8..58e8f1407 100644
--- a/extensions/standard-processors/controllers/JsonTreeReader.h
+++ b/extensions/standard-processors/controllers/JsonTreeReader.h
@@ -43,6 +43,7 @@ class JsonTreeReader final : public core::RecordSetReaderImpl 
{
   EXTENSIONAPI static constexpr auto Properties = 
std::array<core::PropertyReference, 0>{};
 
   EXTENSIONAPI static constexpr bool SupportsDynamicProperties = false;
+  EXTENSIONAPI static constexpr auto ImplementsApis = std::array{ 
RecordSetReader::ProvidesApi };
   ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_CONTROLLER_SERVICES
 
   nonstd::expected<core::RecordSet, std::error_code> read(const 
std::shared_ptr<core::FlowFile>& flow_file, core::ProcessSession& session) 
override;
diff --git a/extensions/standard-processors/modbus/FetchModbusTcp.cpp 
b/extensions/standard-processors/modbus/FetchModbusTcp.cpp
index 516a3e9a4..8e39db378 100644
--- a/extensions/standard-processors/modbus/FetchModbusTcp.cpp
+++ b/extensions/standard-processors/modbus/FetchModbusTcp.cpp
@@ -61,7 +61,7 @@ void FetchModbusTcp::onSchedule(core::ProcessContext& 
context, core::ProcessSess
   ssl_context_.reset();
   if (const auto controller_service_name = 
context.getProperty(SSLContextService); controller_service_name && 
!IsNullOrEmpty(*controller_service_name)) {
     if (auto controller_service = 
context.getControllerService(*controller_service_name, getUUID())) {
-      if (const auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(controller_service))
 {
+      if (const auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(controller_service))
 {
         ssl_context_ = utils::net::getSslContext(*ssl_context_service);
       } else {
         throw Exception(PROCESS_SCHEDULE_EXCEPTION, *controller_service_name + 
" is not an SSL Context Service");
diff --git a/extensions/standard-processors/modbus/FetchModbusTcp.h 
b/extensions/standard-processors/modbus/FetchModbusTcp.h
index 99c0ce6ae..8daafde1c 100644
--- a/extensions/standard-processors/modbus/FetchModbusTcp.h
+++ b/extensions/standard-processors/modbus/FetchModbusTcp.h
@@ -16,8 +16,8 @@
  */
 #pragma once
 
-#include "controllers/SSLContextService.h"
 #include "controllers/RecordSetWriter.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Processor.h"
 #include "core/PropertyDefinitionBuilder.h"
 #include "core/logging/LoggerFactory.h"
@@ -80,7 +80,7 @@ class FetchModbusTcp final : public core::ProcessorImpl {
   EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("The Controller Service to use in order to obtain an 
SSL Context. If this property is set, messages will be sent over a secure 
connection.")
       .isRequired(false)
-      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
       .build();
   EXTENSIONAPI static constexpr auto RecordSetWriter = 
core::PropertyDefinitionBuilder<>::createProperty("Record Set Writer")
       .withDescription("Specifies the Controller Service to use for writing 
results to a FlowFile. ")
diff --git a/extensions/standard-processors/processors/GetTCP.cpp 
b/extensions/standard-processors/processors/GetTCP.cpp
index 7ffef6084..2e51b3ace 100644
--- a/extensions/standard-processors/processors/GetTCP.cpp
+++ b/extensions/standard-processors/processors/GetTCP.cpp
@@ -75,7 +75,7 @@ std::optional<asio::ssl::context> 
GetTCP::parseSSLContext(core::ProcessContext&
   std::optional<asio::ssl::context> ssl_context;
   if (auto context_name = context.getProperty(SSLContextService)) {
     if (auto controller_service = context.getControllerService(*context_name, 
getUUID())) {
-      if (auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(context.getControllerService(*context_name,
 getUUID()))) {
+      if (auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(context.getControllerService(*context_name,
 getUUID()))) {
         ssl_context = utils::net::getSslContext(*ssl_context_service);
       } else {
         throw Exception(PROCESS_SCHEDULE_EXCEPTION, *context_name + " is not 
an SSL Context Service");
diff --git a/extensions/standard-processors/processors/GetTCP.h 
b/extensions/standard-processors/processors/GetTCP.h
index 4313fabed..9562d0c03 100644
--- a/extensions/standard-processors/processors/GetTCP.h
+++ b/extensions/standard-processors/processors/GetTCP.h
@@ -36,7 +36,7 @@
 #include "concurrentqueue.h"
 #include "utils/ThreadPool.h"
 #include "core/logging/LoggerFactory.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "utils/gsl.h"
 #include "utils/Export.h"
 #include "utils/net/AsioSocketUtils.h"
@@ -69,7 +69,7 @@ class GetTCP : public core::ProcessorImpl {
       .build();
   EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("SSL Context Service Name")
-      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
       .build();
   EXTENSIONAPI static constexpr auto MessageDelimiter = 
core::PropertyDefinitionBuilder<>::createProperty("Message Delimiter")
       .withDescription("Character that denotes the end of the message.")
diff --git a/extensions/standard-processors/processors/InvokeHTTP.cpp 
b/extensions/standard-processors/processors/InvokeHTTP.cpp
index 150a947fa..d7226ba64 100644
--- a/extensions/standard-processors/processors/InvokeHTTP.cpp
+++ b/extensions/standard-processors/processors/InvokeHTTP.cpp
@@ -168,7 +168,7 @@ void InvokeHTTP::setupMembersFromProperties(const 
core::ProcessContext& context)
 
   if (auto ssl_context_name = context.getProperty(SSLContext)) {
     if (auto service = context.getControllerService(*ssl_context_name, 
getUUID())) {
-      ssl_context_service_ = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(service);
+      ssl_context_service_ = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(service);
       if (!ssl_context_service_)
         logger_->log_error("Controller service '{}' is not an 
SSLContextService", *ssl_context_name);
     } else {
diff --git a/extensions/standard-processors/processors/InvokeHTTP.h 
b/extensions/standard-processors/processors/InvokeHTTP.h
index feaadef65..3d54491f4 100644
--- a/extensions/standard-processors/processors/InvokeHTTP.h
+++ b/extensions/standard-processors/processors/InvokeHTTP.h
@@ -34,7 +34,7 @@
 #include "core/PropertyDefinitionBuilder.h"
 #include "minifi-cpp/core/PropertyValidator.h"
 #include "core/RelationshipDefinition.h"
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/logging/LoggerFactory.h"
 #include "utils/Id.h"
 #include "utils/ResourceQueue.h"
@@ -176,7 +176,7 @@ class InvokeHTTP : public core::ProcessorImpl {
   EXTENSIONAPI static constexpr auto SSLContext = 
core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("SSL Context Service")
       .withDescription("The SSL Context Service used to provide client 
certificate information for TLS/SSL (https) connections.")
       .isRequired(false)
-      .withAllowedTypes<controllers::SSLContextService>()
+      .withAllowedTypes<controllers::SSLContextServiceInterface>()
       .withExclusiveOfProperties({{{"Remote URL", "^http:.*$"}}})
       .build();
   EXTENSIONAPI static constexpr auto ProxyHost = 
core::PropertyDefinitionBuilder<>::createProperty("Proxy Host")
@@ -359,7 +359,7 @@ class InvokeHTTP : public core::ProcessorImpl {
   std::optional<uint64_t> maximum_upload_speed_ = std::nullopt;
   std::optional<uint64_t> maximum_download_speed_ = std::nullopt;
 
-  std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service_;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service_;
 
   std::chrono::milliseconds connect_timeout_{std::chrono::seconds(30)};
   std::chrono::milliseconds read_timeout_{std::chrono::seconds(30)};
diff --git a/extensions/standard-processors/processors/ListenSyslog.cpp 
b/extensions/standard-processors/processors/ListenSyslog.cpp
index d7653480d..3742329fe 100644
--- a/extensions/standard-processors/processors/ListenSyslog.cpp
+++ b/extensions/standard-processors/processors/ListenSyslog.cpp
@@ -17,8 +17,7 @@
 
 #include "ListenSyslog.h"
 
-
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "core/Resource.h"
diff --git a/extensions/standard-processors/processors/ListenSyslog.h 
b/extensions/standard-processors/processors/ListenSyslog.h
index 71c3273ad..260f20f9d 100644
--- a/extensions/standard-processors/processors/ListenSyslog.h
+++ b/extensions/standard-processors/processors/ListenSyslog.h
@@ -23,7 +23,7 @@
 #include <memory>
 #include <regex>
 
-#include "controllers/SSLContextService.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "NetworkListenerProcessor.h"
 #include "core/logging/LoggerFactory.h"
 #include "core/OutputAttributeDefinition.h"
@@ -79,7 +79,7 @@ class ListenSyslog : public NetworkListenerProcessor {
   EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("The Controller Service to use in order to obtain an 
SSL Context. If this property is set, messages will be received over a secure 
connection. "
           "This Property is only considered if the <Protocol> Property has a 
value of \"TCP\".")
-      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
       .build();
   EXTENSIONAPI static constexpr auto ClientAuth = 
core::PropertyDefinitionBuilder<magic_enum::enum_count<utils::net::ClientAuthOption>()>::createProperty("Client
 Auth")
       .withDescription("The client authentication policy to use for the SSL 
Context. Only used if an SSL Context Service is provided.")
diff --git a/extensions/standard-processors/processors/ListenTCP.cpp 
b/extensions/standard-processors/processors/ListenTCP.cpp
index b2a2b7d39..2aefc6320 100644
--- a/extensions/standard-processors/processors/ListenTCP.cpp
+++ b/extensions/standard-processors/processors/ListenTCP.cpp
@@ -16,9 +16,9 @@
  */
 #include "ListenTCP.h"
 
-#include "core/Resource.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/ProcessContext.h"
-#include "controllers/SSLContextService.h"
+#include "core/Resource.h"
 #include "utils/ProcessorConfigUtils.h"
 
 namespace org::apache::nifi::minifi::processors {
diff --git a/extensions/standard-processors/processors/ListenTCP.h 
b/extensions/standard-processors/processors/ListenTCP.h
index 519783349..4c6634996 100644
--- a/extensions/standard-processors/processors/ListenTCP.h
+++ b/extensions/standard-processors/processors/ListenTCP.h
@@ -20,15 +20,15 @@
 #include <string>
 #include <utility>
 
-#include "controllers/SSLContextService.h"
 #include "NetworkListenerProcessor.h"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Core.h"
-#include "core/logging/LoggerFactory.h"
 #include "core/OutputAttributeDefinition.h"
 #include "core/PropertyDefinition.h"
 #include "core/PropertyDefinitionBuilder.h"
-#include "minifi-cpp/core/PropertyValidator.h"
 #include "core/RelationshipDefinition.h"
+#include "core/logging/LoggerFactory.h"
+#include "minifi-cpp/core/PropertyValidator.h"
 #include "utils/Enum.h"
 #include "utils/net/Ssl.h"
 
@@ -63,7 +63,7 @@ class ListenTCP : public NetworkListenerProcessor {
       .build();
   EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("The Controller Service to use in order to obtain an 
SSL Context. If this property is set, messages will be received over a secure 
connection.")
-      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
       .build();
   EXTENSIONAPI static constexpr auto ClientAuth = 
core::PropertyDefinitionBuilder<magic_enum::enum_count<utils::net::ClientAuthOption>()>::createProperty("Client
 Auth")
       .withDescription("The client authentication policy to use for the SSL 
Context. Only used if an SSL Context Service is provided.")
diff --git a/extensions/standard-processors/processors/ListenUDP.cpp 
b/extensions/standard-processors/processors/ListenUDP.cpp
index 8db44a747..d6f81cd63 100644
--- a/extensions/standard-processors/processors/ListenUDP.cpp
+++ b/extensions/standard-processors/processors/ListenUDP.cpp
@@ -16,8 +16,8 @@
  */
 #include "ListenUDP.h"
 
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Resource.h"
-#include "controllers/SSLContextService.h"
 #include "utils/ProcessorConfigUtils.h"
 
 namespace org::apache::nifi::minifi::processors {
diff --git a/extensions/standard-processors/processors/PutTCP.cpp 
b/extensions/standard-processors/processors/PutTCP.cpp
index b7290d1f6..7e0d1bcc1 100644
--- a/extensions/standard-processors/processors/PutTCP.cpp
+++ b/extensions/standard-processors/processors/PutTCP.cpp
@@ -78,7 +78,7 @@ void PutTCP::onSchedule(core::ProcessContext& context, 
core::ProcessSessionFacto
   ssl_context_.reset();
   if (const auto context_name = context.getProperty(SSLContextService); 
context_name && !IsNullOrEmpty(*context_name)) {
     if (auto controller_service = context.getControllerService(*context_name, 
getUUID())) {
-      if (const auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(context.getControllerService(*context_name,
 getUUID()))) {
+      if (const auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(context.getControllerService(*context_name,
 getUUID()))) {
         ssl_context_ = utils::net::getSslContext(*ssl_context_service);
       } else {
         throw Exception(PROCESS_SCHEDULE_EXCEPTION, *context_name + " is not 
an SSL Context Service");
diff --git a/extensions/standard-processors/processors/PutTCP.h 
b/extensions/standard-processors/processors/PutTCP.h
index 0d8b7abfe..1b574033f 100644
--- a/extensions/standard-processors/processors/PutTCP.h
+++ b/extensions/standard-processors/processors/PutTCP.h
@@ -17,29 +17,29 @@
 
 #pragma once
 
+
 #include <cstddef>
 #include <memory>
 #include <string>
-#include <vector>
 #include <unordered_map>
 #include <utility>
+#include <vector>
 
-#include "io/InputStream.h"
-#include "core/Processor.h"
-#include "utils/Export.h"
-#include "controllers/SSLContextService.h"
+#include "asio/io_context.hpp"
+#include "asio/ssl/context.hpp"
+#include "controllers/SSLContextServiceInterface.h"
 #include "core/Core.h"
+#include "core/Processor.h"
 #include "core/PropertyDefinition.h"
 #include "core/PropertyDefinitionBuilder.h"
-#include "minifi-cpp/core/PropertyValidator.h"
 #include "core/RelationshipDefinition.h"
+#include "io/InputStream.h"
+#include "minifi-cpp/core/PropertyValidator.h"
+#include "utils/Export.h"
 #include "utils/StringUtils.h"  // for string <=> on libc++
 #include "utils/net/AsioSocketUtils.h"
 #include "utils/net/ConnectionHandler.h"
 
-#include <asio/io_context.hpp>
-#include <asio/ssl/context.hpp>
-
 namespace org::apache::nifi::minifi::processors {
 
 
@@ -97,7 +97,7 @@ class PutTCP final : public core::ProcessorImpl {
   EXTENSIONAPI static constexpr auto SSLContextService = 
core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service")
       .withDescription("The Controller Service to use in order to obtain an 
SSL Context. If this property is set, messages will be sent over a secure 
connection.")
       .isRequired(false)
-      .withAllowedTypes<minifi::controllers::SSLContextService>()
+      .withAllowedTypes<minifi::controllers::SSLContextServiceInterface>()
       .build();
   EXTENSIONAPI static constexpr auto MaxSizeOfSocketSendBuffer = 
core::PropertyDefinitionBuilder<>::createProperty("Max Size of Socket Send 
Buffer")
       .withDescription("The maximum size of the socket send buffer that should 
be used. This is a suggestion to the Operating System to indicate how big the 
socket buffer should be.")
diff --git 
a/extensions/standard-processors/tests/integration/VerifyInvokeHTTP.h 
b/extensions/standard-processors/tests/integration/VerifyInvokeHTTP.h
index a05b6005a..e30af2c46 100644
--- a/extensions/standard-processors/tests/integration/VerifyInvokeHTTP.h
+++ b/extensions/standard-processors/tests/integration/VerifyInvokeHTTP.h
@@ -51,7 +51,7 @@ class VerifyInvokeHTTP : public HTTPIntegrationBase {
     
LogTestController::getInstance().setTrace<minifi::processors::LogAttribute>();
     LogTestController::getInstance().setDebug<core::Processor>();
     LogTestController::getInstance().setDebug<core::ProcessSession>();
-    
LogTestController::getInstance().setDebug<minifi::controllers::SSLContextService>();
+    
LogTestController::getInstance().setDebug<minifi::controllers::SSLContextServiceInterface>();
   }
 
   void setUrl(const std::string &url, ServerAwareHandler *handler) override {
diff --git a/extensions/standard-processors/tests/unit/GetTCPTests.cpp 
b/extensions/standard-processors/tests/unit/GetTCPTests.cpp
index d167108e9..d7fd4aaff 100644
--- a/extensions/standard-processors/tests/unit/GetTCPTests.cpp
+++ b/extensions/standard-processors/tests/unit/GetTCPTests.cpp
@@ -50,9 +50,9 @@ void addSslContextServiceTo(SingleProcessorTestController& 
controller) {
   auto ssl_context_service = 
controller.plan->addController("SSLContextService", "SSLContextService");
   LogTestController::getInstance().setTrace<GetTCP>();
   const auto executable_dir = 
minifi::utils::file::FileUtils::get_executable_dir();
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::CACertificate, (executable_dir / 
"resources" / "ca_A.crt").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::ClientCertificate, (executable_dir / 
"resources" / "alice_by_A.pem").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::PrivateKey, (executable_dir / "resources" / 
"alice.key").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::CACertificate, (executable_dir / "resources" / 
"ca_A.crt").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::ClientCertificate, (executable_dir / 
"resources" / "alice_by_A.pem").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::PrivateKey, (executable_dir / "resources" / 
"alice.key").string()));
   ssl_context_service->enable();
 }
 
diff --git a/extensions/standard-processors/tests/unit/ListenSyslogTests.cpp 
b/extensions/standard-processors/tests/unit/ListenSyslogTests.cpp
index 8512173ee..b206fbd16 100644
--- a/extensions/standard-processors/tests/unit/ListenSyslogTests.cpp
+++ b/extensions/standard-processors/tests/unit/ListenSyslogTests.cpp
@@ -495,9 +495,9 @@ TEST_CASE("Test ListenSyslog via TCP with SSL connection", 
"[ListenSyslog][Netwo
 
   auto ssl_context_service = 
controller.plan->addController("SSLContextService", "SSLContextService");
   const auto executable_dir = 
minifi::utils::file::FileUtils::get_executable_dir();
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::CACertificate, (executable_dir / 
"resources" / "ca_A.crt").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::ClientCertificate, (executable_dir / 
"resources" / "localhost_by_A.pem").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::PrivateKey, (executable_dir / "resources" / 
"localhost.key").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::CACertificate, (executable_dir / "resources" / 
"ca_A.crt").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::ClientCertificate, (executable_dir / 
"resources" / "localhost_by_A.pem").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::PrivateKey, (executable_dir / "resources" / 
"localhost.key").string()));
   ssl_context_service->enable();
 
   LogTestController::getInstance().setTrace<ListenSyslog>();
diff --git a/extensions/standard-processors/tests/unit/ListenTcpTests.cpp 
b/extensions/standard-processors/tests/unit/ListenTcpTests.cpp
index d5f6392f3..1daaf530f 100644
--- a/extensions/standard-processors/tests/unit/ListenTcpTests.cpp
+++ b/extensions/standard-processors/tests/unit/ListenTcpTests.cpp
@@ -117,10 +117,10 @@ TEST_CASE("Test ListenTCP with SSL connection", 
"[ListenTCP][NetworkListenerProc
   auto ssl_context_service = 
controller.plan->addController("SSLContextService", "SSLContextService");
   LogTestController::getInstance().setTrace<ListenTCP>();
   const auto executable_dir = 
minifi::utils::file::FileUtils::get_executable_dir();
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::CACertificate, (executable_dir / 
"resources" / "ca_A.crt").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::ClientCertificate, (executable_dir / 
"resources" / "localhost_by_A.pem").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::PrivateKey, (executable_dir / "resources" / 
"localhost.key").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::Passphrase, "Password12"));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::CACertificate, (executable_dir / "resources" / 
"ca_A.crt").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::ClientCertificate, (executable_dir / 
"resources" / "localhost_by_A.pem").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::PrivateKey, (executable_dir / "resources" / 
"localhost.key").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::Passphrase, "Password12"));
   REQUIRE(controller.plan->setProperty(listen_tcp, ListenTCP::MaxBatchSize, 
"2"));
   REQUIRE(controller.plan->setProperty(listen_tcp, 
ListenTCP::SSLContextService, "SSLContextService"));
   std::vector<std::string> expected_successful_messages;
@@ -246,10 +246,10 @@ TEST_CASE("Test ListenTCP SSL/TLS compatibility", 
"[ListenTCP][NetworkListenerPr
   auto ssl_context_service = 
controller.plan->addController("SSLContextService", "SSLContextService");
   LogTestController::getInstance().setTrace<ListenTCP>();
   const auto executable_dir = 
minifi::utils::file::FileUtils::get_executable_dir();
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::CACertificate, (executable_dir / 
"resources" / "ca_A.crt").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::ClientCertificate, (executable_dir / 
"resources" / "localhost_by_A.pem").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::PrivateKey, (executable_dir / "resources" / 
"localhost.key").string()));
-  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextServiceImpl::Passphrase, "Password12"));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::CACertificate, (executable_dir / "resources" / 
"ca_A.crt").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::ClientCertificate, (executable_dir / 
"resources" / "localhost_by_A.pem").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::PrivateKey, (executable_dir / "resources" / 
"localhost.key").string()));
+  REQUIRE(controller.plan->setProperty(ssl_context_service, 
controllers::SSLContextService::Passphrase, "Password12"));
   REQUIRE(controller.plan->setProperty(listen_tcp, ListenTCP::MaxBatchSize, 
"2"));
   REQUIRE(controller.plan->setProperty(listen_tcp, 
ListenTCP::SSLContextService, "SSLContextService"));
   REQUIRE(controller.plan->setProperty(listen_tcp, ListenTCP::ClientAuth, 
"REQUIRED"));
diff --git a/extensions/standard-processors/tests/unit/ManifestTests.cpp 
b/extensions/standard-processors/tests/unit/ManifestTests.cpp
index 68dadc44e..2e04ca3db 100644
--- a/extensions/standard-processors/tests/unit/ManifestTests.cpp
+++ b/extensions/standard-processors/tests/unit/ManifestTests.cpp
@@ -217,3 +217,155 @@ TEST_CASE("Compiled but not loaded extensions are not 
included in the manifest")
   CHECK(ranges::contains(extensions, "minifi-standard-processors"));
   CHECK_FALSE(ranges::contains(extensions, "minifi-test-processors"));
 }
+
+enum ComponentType {
+  kProcessor,
+  kControllerService,
+};
+
+struct AllowedType {
+  std::string type;
+  std::string group;
+  std::string artifact;
+
+  auto operator<=>(const AllowedType&) const = default;
+};
+
+using minifi::state::response::SerializedResponseNode;
+
+const SerializedResponseNode* getBundle(const 
std::vector<SerializedResponseNode>& manifest, const std::string_view 
bundle_artifact_name) {
+  const auto bundle_it = ranges::find_if(manifest, 
[bundle_artifact_name](const auto& node) {
+    return node.name == "bundles" && std::end(node.children) != 
ranges::find_if(node.children, [bundle_artifact_name](const auto& child) {
+      return child.name == "artifact" && child.value.to_string() == 
bundle_artifact_name;
+    });
+  });
+  if (bundle_it == std::end(manifest)) {
+    return nullptr;
+  }
+  return &(*bundle_it);
+}
+
+
+const SerializedResponseNode* getComponentFromBundle(const auto& bundle, const 
std::string_view name, const ComponentType type) {
+  const auto component_manifest = ranges::find_if(bundle.children, [](const 
auto& bundle_child) { return bundle_child.name == "componentManifest"; });
+  if (component_manifest == std::end(bundle.children)) {
+    return nullptr;
+  }
+  if (type == ComponentType::kProcessor) {
+    const auto processors = ranges::find_if(component_manifest->children, 
[](const auto& c) { return c.name == "processors"; });
+    if (processors != std::end(component_manifest->children)) {
+      const auto proc_it = ranges::find_if(processors->children, [name](const 
auto& c) { return c.name == name; });
+      if (proc_it != std::end(processors->children)) {
+        return &(*proc_it);
+      }
+    }
+  } else if (type == ComponentType::kControllerService) {
+    const auto controller_services = 
ranges::find_if(component_manifest->children, [](const auto& c) { return c.name 
== "controllerServices"; });
+    if (controller_services != std::end(component_manifest->children)) {
+      const auto controller_service_it = 
ranges::find_if(controller_services->children, [name](const auto& c) { return 
c.name == name; });
+      if (controller_service_it != std::end(controller_services->children)) {
+        return &(*controller_service_it);
+      }
+    }
+  }
+  return nullptr;
+}
+
+std::optional<AllowedType> getProcessorPropertyAllowedType(const 
SerializedResponseNode& processor_node, const std::string_view property) {
+  const auto property_descriptors = ranges::find_if(processor_node.children, 
[](const auto& c) { return c.name == "propertyDescriptors"; });
+  if (property_descriptors == std::end(processor_node.children)) {
+    return std::nullopt;
+  }
+  const auto property_descriptor = 
ranges::find_if(property_descriptors->children, [property](const auto& c) { 
return c.name == property; });
+  if (property_descriptor == std::end(property_descriptors->children)) {
+    return std::nullopt;
+  }
+  const auto type_provided_by_value = 
ranges::find_if(property_descriptor->children, [](const auto& c) { return 
c.name == "typeProvidedByValue"; });
+  if (type_provided_by_value == std::end(property_descriptor->children)) {
+    return std::nullopt;
+  }
+  const auto artifact_node = ranges::find_if(type_provided_by_value->children, 
[](const auto& c) { return c.name == "artifact"; });
+  const auto group_node = ranges::find_if(type_provided_by_value->children, 
[](const auto& c) { return c.name == "group"; });
+  const auto type_node = ranges::find_if(type_provided_by_value->children, 
[](const auto& c) { return c.name == "type"; });
+  if (artifact_node == std::end(type_provided_by_value->children) || 
group_node == std::end(type_provided_by_value->children) || type_node == 
std::end(type_provided_by_value->children)) {
+    return std::nullopt;
+  }
+  return AllowedType{
+    .type = type_node->value.to_string(),
+    .group = group_node->value.to_string(),
+    .artifact = artifact_node->value.to_string()};
+}
+
+std::vector<AllowedType> getControllerServiceProvidedApiImplementations(const 
SerializedResponseNode& controller_service_node) {
+  std::vector<AllowedType> allowed_types;
+  const auto provided_api_implementations = 
ranges::find_if(controller_service_node.children, [](const auto& c) { return 
c.name == "providedApiImplementations"; });
+  if (provided_api_implementations == 
std::end(controller_service_node.children)) {
+    return allowed_types;
+  }
+  for (const auto& provided_api_implementation : 
provided_api_implementations->children) {
+    const auto artifact_node = 
ranges::find_if(provided_api_implementation.children, [](const auto& c) { 
return c.name == "artifact"; });
+    const auto group_node = 
ranges::find_if(provided_api_implementation.children, [](const auto& c) { 
return c.name == "group"; });
+    const auto type_node = 
ranges::find_if(provided_api_implementation.children, [](const auto& c) { 
return c.name == "type"; });
+    if (artifact_node == std::end(provided_api_implementation.children)
+      || group_node == std::end(provided_api_implementation.children)
+      || type_node == std::end(provided_api_implementation.children)) {
+      continue;
+    }
+    allowed_types.push_back({
+      .type = type_node->value.to_string(),
+      .group = group_node->value.to_string(),
+      .artifact = artifact_node->value.to_string()});
+  }
+  return allowed_types;
+}
+
+TEST_CASE("Test providedApiImplementations") {
+  minifi::state::response::AgentManifest manifest("minifi-system");
+  const auto manifest_serialized = manifest.serialize();
+
+  const auto minifi_system_bundle = getBundle(manifest_serialized, 
"minifi-system");
+  const auto minifi_standard_processors_bundle = 
getBundle(manifest_serialized, "minifi-standard-processors");
+
+  REQUIRE(minifi_system_bundle);
+  REQUIRE(minifi_standard_processors_bundle);
+
+  {
+    const auto ssl_context_service = 
getComponentFromBundle(*minifi_system_bundle, 
"org.apache.nifi.minifi.controllers.SSLContextService", 
ComponentType::kControllerService);
+    const auto listen_tcp = 
getComponentFromBundle(*minifi_standard_processors_bundle, 
"org.apache.nifi.minifi.processors.ListenTCP", ComponentType::kProcessor);
+
+    REQUIRE(ssl_context_service);
+    REQUIRE(listen_tcp);
+
+    const auto listen_tcp_ssl_context_service_allowed_type = 
getProcessorPropertyAllowedType(*listen_tcp, "SSL Context Service");
+    const auto ssl_context_service_provided_api_imps = 
getControllerServiceProvidedApiImplementations(*ssl_context_service);
+
+    REQUIRE(listen_tcp_ssl_context_service_allowed_type);
+    REQUIRE(ssl_context_service_provided_api_imps.size() == 1);
+    CHECK(*listen_tcp_ssl_context_service_allowed_type == 
ssl_context_service_provided_api_imps[0]);
+  }
+
+  {
+    const auto json_tree_reader = 
getComponentFromBundle(*minifi_standard_processors_bundle, 
"org.apache.nifi.minifi.standard.JsonTreeReader", 
ComponentType::kControllerService);
+    const auto json_record_set_writer = 
getComponentFromBundle(*minifi_standard_processors_bundle, 
"org.apache.nifi.minifi.standard.JsonRecordSetWriter", 
ComponentType::kControllerService);
+    const auto split_record = 
getComponentFromBundle(*minifi_standard_processors_bundle, 
"org.apache.nifi.minifi.processors.SplitRecord", ComponentType::kProcessor);
+
+    REQUIRE(json_tree_reader);
+    REQUIRE(json_record_set_writer);
+    REQUIRE(split_record);
+
+    const auto split_record_record_reader_allowed_type = 
getProcessorPropertyAllowedType(*split_record, "Record Reader");
+    const auto split_record_record_writer_allowed_type = 
getProcessorPropertyAllowedType(*split_record, "Record Writer");
+
+    const auto json_tree_reader_api_imps = 
getControllerServiceProvidedApiImplementations(*json_tree_reader);
+    const auto json_record_set_writer_api_imps = 
getControllerServiceProvidedApiImplementations(*json_record_set_writer);
+
+    REQUIRE(split_record_record_reader_allowed_type);
+    REQUIRE(split_record_record_writer_allowed_type);
+
+    REQUIRE(json_tree_reader_api_imps.size() == 1);
+    REQUIRE(json_record_set_writer_api_imps.size() == 1);
+
+    CHECK(*split_record_record_reader_allowed_type == 
json_tree_reader_api_imps[0]);
+    CHECK(*split_record_record_writer_allowed_type == 
json_record_set_writer_api_imps[0]);
+  }
+}
diff --git a/extensions/standard-processors/tests/unit/PutTCPTests.cpp 
b/extensions/standard-processors/tests/unit/PutTCPTests.cpp
index ad6590203..ccac79638 100644
--- a/extensions/standard-processors/tests/unit/PutTCPTests.cpp
+++ b/extensions/standard-processors/tests/unit/PutTCPTests.cpp
@@ -36,7 +36,7 @@ using 
org::apache::nifi::minifi::test::utils::verifyEventHappenedInPollTime;
 
 namespace org::apache::nifi::minifi::processors {
 
-using controllers::SSLContextServiceImpl;
+using controllers::SSLContextService;
 
 namespace {
 
@@ -170,12 +170,12 @@ class PutTCPTestFixture {
   void addSSLContextToPutTCP(const std::filesystem::path& ca_cert, const 
std::optional<std::filesystem::path>& client_cert, const 
std::optional<std::filesystem::path>& client_cert_key) {
     const std::filesystem::path ca_dir = 
minifi::utils::file::FileUtils::get_executable_dir() / "resources";
     auto ssl_context_service_node = 
controller_.plan->addController("SSLContextService", "SSLContextService");
-    REQUIRE(controller_.plan->setProperty(ssl_context_service_node, 
SSLContextServiceImpl::CACertificate, (ca_dir / ca_cert).string()));
+    REQUIRE(controller_.plan->setProperty(ssl_context_service_node, 
SSLContextService::CACertificate, (ca_dir / ca_cert).string()));
     if (client_cert) {
-      REQUIRE(controller_.plan->setProperty(ssl_context_service_node, 
SSLContextServiceImpl::ClientCertificate, (ca_dir / *client_cert).string()));
+      REQUIRE(controller_.plan->setProperty(ssl_context_service_node, 
SSLContextService::ClientCertificate, (ca_dir / *client_cert).string()));
     }
     if (client_cert_key) {
-      REQUIRE(controller_.plan->setProperty(ssl_context_service_node, 
SSLContextServiceImpl::PrivateKey, (ca_dir / *client_cert_key).string()));
+      REQUIRE(controller_.plan->setProperty(ssl_context_service_node, 
SSLContextService::PrivateKey, (ca_dir / *client_cert_key).string()));
     }
     ssl_context_service_node->enable();
 
diff --git a/libminifi/include/RemoteProcessorGroupPort.h 
b/libminifi/include/RemoteProcessorGroupPort.h
index 2f1e5bbb2..52a4e2bcb 100644
--- a/libminifi/include/RemoteProcessorGroupPort.h
+++ b/libminifi/include/RemoteProcessorGroupPort.h
@@ -35,7 +35,7 @@
 #include "core/PropertyDefinitionBuilder.h"
 #include "core/RelationshipDefinition.h"
 #include "sitetosite/SiteToSiteClient.h"
-#include "minifi-cpp/controllers/SSLContextService.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 #include "core/logging/LoggerFactory.h"
 #include "utils/Export.h"
 #include "core/ClassLoader.h"
@@ -248,7 +248,7 @@ class RemoteProcessorGroupPort : public core::ProcessorImpl 
{
   std::string rest_user_name_;
   std::string rest_password_;
 
-  std::shared_ptr<controllers::SSLContextService> ssl_service;
+  std::shared_ptr<controllers::SSLContextServiceInterface> ssl_service;
 
  private:
   std::shared_ptr<core::logging::Logger> logger_;
diff --git a/libminifi/include/c2/ControllerSocketProtocol.h 
b/libminifi/include/c2/ControllerSocketProtocol.h
index 3bdab8688..6823c5d63 100644
--- a/libminifi/include/c2/ControllerSocketProtocol.h
+++ b/libminifi/include/c2/ControllerSocketProtocol.h
@@ -32,7 +32,7 @@
 #include "asio/ip/tcp.hpp"
 #include "asio/ssl/context.hpp"
 #include "utils/net/AsioCoro.h"
-#include "controllers/SSLContextService.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 
 namespace org::apache::nifi::minifi::c2 {
 
@@ -62,10 +62,10 @@ class ControllerSocketProtocol {
   void writeDebugBundleResponse(io::BaseStream &stream);
   void handleDescribe(io::BaseStream &stream);
   asio::awaitable<void> handleCommand(std::unique_ptr<io::BaseStream> stream);
-  asio::awaitable<void> handshakeAndHandleCommand(asio::ip::tcp::socket&& 
socket, std::shared_ptr<minifi::controllers::SSLContextService> 
ssl_context_service);
+  asio::awaitable<void> handshakeAndHandleCommand(asio::ip::tcp::socket&& 
socket, std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service);
   std::string getJstack();
   asio::awaitable<void> startAccept();
-  asio::awaitable<void> 
startAcceptSsl(std::shared_ptr<minifi::controllers::SSLContextService> 
ssl_context_service);
+  asio::awaitable<void> 
startAcceptSsl(std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service);
   void stopListener();
 
   core::controller::ControllerServiceProvider& controller_;
diff --git a/libminifi/include/c2/protocols/RESTSender.h 
b/libminifi/include/c2/protocols/RESTSender.h
index 4daf6e0cf..f20283ae3 100644
--- a/libminifi/include/c2/protocols/RESTSender.h
+++ b/libminifi/include/c2/protocols/RESTSender.h
@@ -23,7 +23,7 @@
 
 #include "c2/C2Protocol.h"
 #include "c2/protocols/RESTProtocol.h"
-#include "minifi-cpp/controllers/SSLContextService.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 #include "http/HTTPClient.h"
 #include "utils/Enum.h"
 
@@ -70,7 +70,7 @@ class RESTSender : public RESTProtocol, public C2Protocol {
    */
   void setSecurityContext(http::HTTPClient &client, http::HttpRequestMethod 
type, const std::string &url);
 
-  std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service_;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service_;
 
   std::string rest_uri_;
   std::string ack_uri_;
diff --git a/libminifi/include/controllers/NetworkPrioritizerService.h 
b/libminifi/include/controllers/NetworkPrioritizerService.h
index 8063a101a..0c4a5204b 100644
--- a/libminifi/include/controllers/NetworkPrioritizerService.h
+++ b/libminifi/include/controllers/NetworkPrioritizerService.h
@@ -25,7 +25,6 @@
 
 #include "utils/StringUtils.h"
 #include "io/validation.h"
-#include "controllers/SSLContextService.h"
 #include "core/controller/ControllerService.h"
 #include "core/logging/LoggerFactory.h"
 #include "core/PropertyDefinition.h"
diff --git a/libminifi/include/controllers/SSLContextService.h 
b/libminifi/include/controllers/SSLContextService.h
index 9344d4191..8d7e3d738 100644
--- a/libminifi/include/controllers/SSLContextService.h
+++ b/libminifi/include/controllers/SSLContextService.h
@@ -25,28 +25,28 @@
 #include <wincrypt.h>
 #endif
 
-#include <openssl/err.h>
-#include <openssl/ssl.h>
-#include <openssl/bio.h>
-#include <openssl/pkcs12.h>
-
 #include <iostream>
 #include <memory>
 #include <string>
 #include <utility>
 
-#include "utils/StringUtils.h"
-#include "utils/tls/ExtendedKeyUsage.h"
-#include "io/validation.h"
-#include "core/controller/ControllerService.h"
-#include "core/logging/LoggerFactory.h"
+#include "openssl/bio.h"
+#include "openssl/err.h"
+#include "openssl/pkcs12.h"
+#include "openssl/ssl.h"
+
 #include "core/PropertyDefinition.h"
 #include "core/PropertyDefinitionBuilder.h"
+#include "core/controller/ControllerService.h"
+#include "core/logging/LoggerFactory.h"
+#include "io/validation.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 #include "minifi-cpp/core/PropertyValidator.h"
 #include "utils/ConfigurationUtils.h"
 #include "utils/Export.h"
+#include "utils/StringUtils.h"
 #include "utils/tls/CertificateUtils.h"
-#include "minifi-cpp/controllers/SSLContextService.h"
+#include "utils/tls/ExtendedKeyUsage.h"
 
 namespace org::apache::nifi::minifi::controllers {
 
@@ -72,20 +72,20 @@ class SSLContext {
  * Justification: Abstracts SSL support out of processors into a
  * configurable controller service.
  */
-class SSLContextServiceImpl : public core::controller::ControllerServiceImpl, 
public SSLContextService {
+class SSLContextService : public core::controller::ControllerServiceImpl, 
public SSLContextServiceInterface {
  public:
-  explicit SSLContextServiceImpl(std::string_view name, const 
utils::Identifier &uuid = {})
+  explicit SSLContextService(std::string_view name, const utils::Identifier 
&uuid = {})
       : ControllerServiceImpl(name, uuid),
         initialized_(false),
         
logger_(core::logging::LoggerFactory<SSLContextService>::getLogger(uuid_)) {
   }
 
-  explicit SSLContextServiceImpl(std::string_view name, const 
std::shared_ptr<Configure> &configuration)
+  explicit SSLContextService(std::string_view name, const 
std::shared_ptr<Configure> &configuration)
       : ControllerServiceImpl(name),
         initialized_(false),
         
logger_(core::logging::LoggerFactory<SSLContextService>::getLogger(uuid_)) {
     ControllerServiceImpl::setConfiguration(configuration);
-    SSLContextServiceImpl::initialize();
+    SSLContextService::initialize();
     auto setPropertyAndHandleError = [this](std::string_view property_name, 
std::string value) {
       auto result = ControllerServiceImpl::setProperty(property_name, 
std::move(value));
       if (!result) {
@@ -138,6 +138,8 @@ class SSLContextServiceImpl : public 
core::controller::ControllerServiceImpl, pu
 #endif  // WIN32
   }
 
+  static constexpr auto ImplementsApis = std::array{ 
SSLContextServiceInterface::ProvidesApi };
+
   void initialize() override;
 
   std::unique_ptr<SSLContext> createSSLContext();
diff --git a/libminifi/include/core/logging/alert/AlertSink.h 
b/libminifi/include/core/logging/alert/AlertSink.h
index 45d7f58f6..909574089 100644
--- a/libminifi/include/core/logging/alert/AlertSink.h
+++ b/libminifi/include/core/logging/alert/AlertSink.h
@@ -34,7 +34,7 @@
 #include "spdlog/sinks/base_sink.h"
 
 namespace org::apache::nifi::minifi::controllers {
-class SSLContextService;
+class SSLContextServiceInterface;
 }  // namespace org::apache::nifi::minifi::controllers
 
 namespace org::apache::nifi::minifi::core::logging {
@@ -65,7 +65,7 @@ class AlertSink : public spdlog::sinks::base_sink<std::mutex> 
{
   };
 
   struct Services {
-    std::shared_ptr<controllers::SSLContextService> ssl_service;
+    std::shared_ptr<controllers::SSLContextServiceInterface> ssl_service;
     std::shared_ptr<AgentIdentificationProvider> agent_id;
   };
 
diff --git a/libminifi/include/sitetosite/SiteToSite.h 
b/libminifi/include/sitetosite/SiteToSite.h
index 5270919d1..178d6730a 100644
--- a/libminifi/include/sitetosite/SiteToSite.h
+++ b/libminifi/include/sitetosite/SiteToSite.h
@@ -21,7 +21,7 @@
 #include <string>
 #include <utility>
 
-#include "minifi-cpp/controllers/SSLContextService.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 #include "Peer.h"
 #include "core/Property.h"
 #include "properties/Configure.h"
@@ -341,11 +341,11 @@ class SiteToSiteClientConfiguration {
     return peer_;
   }
 
-  void setSecurityContext(const 
std::shared_ptr<controllers::SSLContextService> &ssl_service) {
+  void setSecurityContext(const 
std::shared_ptr<controllers::SSLContextServiceInterface> &ssl_service) {
     ssl_service_ = ssl_service;
   }
 
-  const std::shared_ptr<controllers::SSLContextService> &getSecurityContext() 
const {
+  const std::shared_ptr<controllers::SSLContextServiceInterface> 
&getSecurityContext() const {
     return ssl_service_;
   }
 
@@ -382,7 +382,7 @@ class SiteToSiteClientConfiguration {
 
   // secore comms
 
-  std::shared_ptr<controllers::SSLContextService> ssl_service_;
+  std::shared_ptr<controllers::SSLContextServiceInterface> ssl_service_;
 
   http::HTTPProxy proxy_;
 };
diff --git a/libminifi/include/sitetosite/SiteToSiteClient.h 
b/libminifi/include/sitetosite/SiteToSiteClient.h
index da4763f9c..6d4d2e913 100644
--- a/libminifi/include/sitetosite/SiteToSiteClient.h
+++ b/libminifi/include/sitetosite/SiteToSiteClient.h
@@ -62,7 +62,7 @@ class SiteToSiteClient : public core::ConnectableImpl {
 
   ~SiteToSiteClient() override = default;
 
-  void setSSLContextService(const 
std::shared_ptr<minifi::controllers::SSLContextService> &context_service) {
+  void setSSLContextService(const 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
&context_service) {
     ssl_context_service_ = context_service;
   }
 
@@ -255,7 +255,7 @@ class SiteToSiteClient : public core::ConnectableImpl {
   int _currentCodecVersionIndex{0};
   uint32_t 
_currentCodecVersion{_supportedCodecVersion[_currentCodecVersionIndex]};
 
-  std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service_;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service_;
 
  private:
   std::shared_ptr<core::logging::Logger> 
logger_{core::logging::LoggerFactory<SiteToSiteClient>::getLogger()};
diff --git a/libminifi/src/RemoteProcessorGroupPort.cpp 
b/libminifi/src/RemoteProcessorGroupPort.cpp
index 96f77efdc..144a8f5ab 100644
--- a/libminifi/src/RemoteProcessorGroupPort.cpp
+++ b/libminifi/src/RemoteProcessorGroupPort.cpp
@@ -20,24 +20,22 @@
 
 #include "RemoteProcessorGroupPort.h"
 
-#include <memory>
+#include <cinttypes>
 #include <iostream>
-#include <vector>
+#include <memory>
 #include <string>
 #include <utility>
-#include <cinttypes>
+#include <vector>
 
-#include "sitetosite/Peer.h"
 #include "Exception.h"
-#include "sitetosite/SiteToSiteFactory.h"
-
-#include "rapidjson/document.h"
-
-#include "core/logging/Logger.h"
+#include "controllers/SSLContextService.h"
 #include "core/ProcessContext.h"
 #include "core/Processor.h"
+#include "core/logging/Logger.h"
 #include "http/BaseHTTPClient.h"
-#include "controllers/SSLContextService.h"
+#include "rapidjson/document.h"
+#include "sitetosite/Peer.h"
+#include "sitetosite/SiteToSiteFactory.h"
 #include "utils/net/DNS.h"
 
 #undef GetObject  // windows.h #defines GetObject = GetObjectA or GetObjectW, 
which conflicts with rapidjson
@@ -122,11 +120,11 @@ void 
RemoteProcessorGroupPort::onSchedule(core::ProcessContext& context, core::P
 
   std::shared_ptr<core::controller::ControllerService> service = 
context.getControllerService(*context_name, getUUID());
   if (nullptr != service) {
-    ssl_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(service);
+    ssl_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(service);
   } else {
     std::string secureStr;
     if (configure_->get(Configure::nifi_remote_input_secure, secureStr) && 
utils::string::toBool(secureStr).value_or(false)) {
-      ssl_service = 
std::make_shared<minifi::controllers::SSLContextServiceImpl>(RPG_SSL_CONTEXT_SERVICE_NAME,
 configure_);
+      ssl_service = 
std::make_shared<minifi::controllers::SSLContextService>(RPG_SSL_CONTEXT_SERVICE_NAME,
 configure_);
       ssl_service->onEnable();
     }
   }
diff --git a/libminifi/src/c2/ControllerSocketProtocol.cpp 
b/libminifi/src/c2/ControllerSocketProtocol.cpp
index 6d1b957b6..09504914e 100644
--- a/libminifi/src/c2/ControllerSocketProtocol.cpp
+++ b/libminifi/src/c2/ControllerSocketProtocol.cpp
@@ -18,21 +18,22 @@
 #include "c2/ControllerSocketProtocol.h"
 
 #include <fstream>
+#include <sstream>
+#include <string>
 #include <utility>
 #include <vector>
-#include <string>
-#include <sstream>
 
-#include "utils/gsl.h"
-#include "utils/StringUtils.h"
+#include "asio/detached.hpp"
+#include "asio/ssl/stream.hpp"
 #include "c2/C2Payload.h"
-#include "properties/Configuration.h"
+#include "c2/C2Utils.h"
+#include "controllers/SSLContextService.h"
 #include "io/AsioStream.h"
-#include "asio/ssl/stream.hpp"
-#include "asio/detached.hpp"
+#include "properties/Configuration.h"
 #include "utils/ConfigurationUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/gsl.h"
 #include "utils/net/AsioSocketUtils.h"
-#include "c2/C2Utils.h"
 
 namespace org::apache::nifi::minifi::c2 {
 
@@ -110,7 +111,7 @@ asio::awaitable<void> 
ControllerSocketProtocol::startAccept() {
   }
 }
 
-asio::awaitable<void> 
ControllerSocketProtocol::handshakeAndHandleCommand(asio::ip::tcp::socket&& 
socket, std::shared_ptr<minifi::controllers::SSLContextService> 
ssl_context_service) {
+asio::awaitable<void> 
ControllerSocketProtocol::handshakeAndHandleCommand(asio::ip::tcp::socket&& 
socket, std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service) {
   asio::ssl::context ssl_context = 
utils::net::getSslContext(*ssl_context_service, asio::ssl::context::tls_server);
   ssl_context.set_options(utils::net::MINIFI_SSL_OPTIONS);
   asio::ssl::stream<asio::ip::tcp::socket> ssl_socket(std::move(socket), 
ssl_context);
@@ -125,7 +126,7 @@ asio::awaitable<void> 
ControllerSocketProtocol::handshakeAndHandleCommand(asio::
   co_return co_await handleCommand(std::move(stream));
 }
 
-asio::awaitable<void> 
ControllerSocketProtocol::startAcceptSsl(std::shared_ptr<minifi::controllers::SSLContextService>
 ssl_context_service) {
+asio::awaitable<void> 
ControllerSocketProtocol::startAcceptSsl(std::shared_ptr<minifi::controllers::SSLContextServiceInterface>
 ssl_context_service) {
   while (true) {  // NOLINT(clang-analyzer-core.NullDereference) suppressing 
asio library linter warning
     auto [accept_error, socket] = co_await 
acceptor_->async_accept(utils::net::use_nothrow_awaitable);
     if (accept_error) {
@@ -143,18 +144,18 @@ asio::awaitable<void> 
ControllerSocketProtocol::startAcceptSsl(std::shared_ptr<m
 
 void ControllerSocketProtocol::initialize() {
   std::unique_lock<std::mutex> lock(initialization_mutex_);
-  std::shared_ptr<minifi::controllers::SSLContextService> secure_context;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
secure_context;
   std::string context_name;
   if (configuration_->get(Configure::controller_ssl_context_service, 
context_name)) {
     std::shared_ptr<core::controller::ControllerService> service = 
controller_.getControllerService(context_name);
     if (nullptr != service) {
-      secure_context = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(service);
+      secure_context = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(service);
     }
   }
   if (nullptr == secure_context) {
     std::string secure_str;
     if (configuration_->get(Configure::nifi_remote_input_secure, secure_str) 
&& 
org::apache::nifi::minifi::utils::string::toBool(secure_str).value_or(false)) {
-      secure_context = 
std::make_shared<minifi::controllers::SSLContextServiceImpl>("ControllerSocketProtocolSSL",
 configuration_);
+      secure_context = 
std::make_shared<minifi::controllers::SSLContextService>("ControllerSocketProtocolSSL",
 configuration_);
       secure_context->onEnable();
     }
   }
diff --git a/libminifi/src/c2/protocols/RESTSender.cpp 
b/libminifi/src/c2/protocols/RESTSender.cpp
index 8265d82b6..56da8b607 100644
--- a/libminifi/src/c2/protocols/RESTSender.cpp
+++ b/libminifi/src/c2/protocols/RESTSender.cpp
@@ -62,13 +62,13 @@ void 
RESTSender::initialize(core::controller::ControllerServiceProvider* control
     }
     if (controller && 
configure->get(Configuration::nifi_c2_rest_ssl_context_service, 
"c2.rest.ssl.context.service", ssl_context_service_str)) {
       if (auto service = 
controller->getControllerService(ssl_context_service_str)) {
-        ssl_context_service_ = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(service);
+        ssl_context_service_ = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(service);
       }
     }
     if (nullptr == ssl_context_service_) {
       std::string ssl_context_str;
       if (configure->get(Configure::nifi_remote_input_secure, ssl_context_str) 
&& 
org::apache::nifi::minifi::utils::string::toBool(ssl_context_str).value_or(false))
 {
-        ssl_context_service_ = 
std::make_shared<minifi::controllers::SSLContextServiceImpl>("RESTSenderSSL", 
configure);
+        ssl_context_service_ = 
std::make_shared<minifi::controllers::SSLContextService>("RESTSenderSSL", 
configure);
         ssl_context_service_->onEnable();
       }
     }
@@ -110,7 +110,7 @@ void RESTSender::update(const std::shared_ptr<Configure> &) 
{
 
 void RESTSender::setSecurityContext(http::HTTPClient &client, 
http::HttpRequestMethod type, const std::string &url) {
   // only use the SSL Context if we have a secure URL.
-  auto generatedService = 
std::make_shared<minifi::controllers::SSLContextServiceImpl>("Service", 
configuration_);
+  auto generatedService = 
std::make_shared<minifi::controllers::SSLContextService>("Service", 
configuration_);
   generatedService->onEnable();
   client.initialize(type, url, generatedService);
 }
diff --git a/libminifi/src/controllers/SSLContextService.cpp 
b/libminifi/src/controllers/SSLContextService.cpp
index decf0210e..5d688c64f 100644
--- a/libminifi/src/controllers/SSLContextService.cpp
+++ b/libminifi/src/controllers/SSLContextService.cpp
@@ -72,7 +72,7 @@ std::string getCertName(const utils::tls::X509_unique_ptr& 
cert) {
 #endif
 }  // namespace
 
-void SSLContextServiceImpl::initialize() {
+void SSLContextService::initialize() {
   std::lock_guard<std::mutex> lock(initialization_mutex_);
   if (initialized_) {
     return;
@@ -85,7 +85,7 @@ void SSLContextServiceImpl::initialize() {
   initialized_ = true;
 }
 
-bool SSLContextServiceImpl::configure_ssl_context(void* raw_ctx) {
+bool SSLContextService::configure_ssl_context(void* raw_ctx) {
   auto* const ctx = static_cast<SSL_CTX*>(raw_ctx);
   if (!certificate_.empty()) {
     if (isFileTypeP12(certificate_)) {
@@ -141,7 +141,7 @@ bool SSLContextServiceImpl::configure_ssl_context(void* 
raw_ctx) {
   return true;
 }
 
-bool SSLContextServiceImpl::addP12CertificateToSSLContext(SSL_CTX* ctx) const {
+bool SSLContextService::addP12CertificateToSSLContext(SSL_CTX* ctx) const {
   auto error = utils::tls::processP12Certificate(certificate_, passphrase_, {
       .cert_cb = [&] (auto cert) -> std::error_code {
         if (SSL_CTX_use_certificate(ctx, cert.get()) != 1) {
@@ -170,7 +170,7 @@ bool 
SSLContextServiceImpl::addP12CertificateToSSLContext(SSL_CTX* ctx) const {
   return true;
 }
 
-bool SSLContextServiceImpl::addPemCertificateToSSLContext(SSL_CTX* ctx) const {
+bool SSLContextService::addPemCertificateToSSLContext(SSL_CTX* ctx) const {
   if (SSL_CTX_use_certificate_chain_file(ctx, certificate_.string().c_str()) 
<= 0) {
     logger_->log_error("Could not load client certificate {}, {}", 
certificate_.string(), getLatestOpenSSLErrorString());
     return false;
@@ -194,7 +194,7 @@ bool 
SSLContextServiceImpl::addPemCertificateToSSLContext(SSL_CTX* ctx) const {
 }
 
 #ifdef WIN32
-bool SSLContextServiceImpl::findClientCertificate(ClientCertCallback cb) const 
{
+bool SSLContextService::findClientCertificate(ClientCertCallback cb) const {
   utils::tls::WindowsCertStore 
cert_store(utils::tls::WindowsCertStoreLocation{cert_store_location_}, 
client_cert_store_);
   if (auto error = cert_store.error()) {
     logger_->log_error("Could not open system certificate store {}/{} (client 
certificates): {}", cert_store_location_, client_cert_store_, error.message());
@@ -216,7 +216,7 @@ bool 
SSLContextServiceImpl::findClientCertificate(ClientCertCallback cb) const {
 #endif
 
 #ifdef WIN32
-bool 
SSLContextServiceImpl::addClientCertificateFromSystemStoreToSSLContext(SSL_CTX* 
ctx) const {
+bool 
SSLContextService::addClientCertificateFromSystemStoreToSSLContext(SSL_CTX* 
ctx) const {
   return findClientCertificate([&] (auto cert, auto priv_key) -> bool {
     auto cert_name = getCertName(cert);
     if (SSL_CTX_use_certificate(ctx, cert.get()) != 1) {
@@ -232,14 +232,14 @@ bool 
SSLContextServiceImpl::addClientCertificateFromSystemStoreToSSLContext(SSL_
   });
 }
 #else
-bool 
SSLContextServiceImpl::addClientCertificateFromSystemStoreToSSLContext(SSL_CTX* 
/*ctx*/) const {
+bool 
SSLContextService::addClientCertificateFromSystemStoreToSSLContext(SSL_CTX* 
/*ctx*/) const {
   logger_->log_error("Getting client certificate from the system store is only 
supported on Windows");
   return false;
 }
 #endif  // WIN32
 
 #ifdef WIN32
-bool SSLContextServiceImpl::useClientCertificate(PCCERT_CONTEXT certificate, 
ClientCertCallback cb) const {
+bool SSLContextService::useClientCertificate(PCCERT_CONTEXT certificate, 
ClientCertCallback cb) const {
   utils::tls::X509_unique_ptr x509_cert = 
utils::tls::convertWindowsCertificate(certificate);
   if (!x509_cert) {
     logger_->log_error("Failed to convert system store client certificate to 
X.509 format");
@@ -283,7 +283,7 @@ bool 
SSLContextServiceImpl::useClientCertificate(PCCERT_CONTEXT certificate, Cli
 }
 #endif  // WIN32
 
-bool 
SSLContextServiceImpl::addServerCertificatesFromSystemStoreToSSLContext(SSL_CTX*
 ctx) const {  // NOLINT(readability-convert-member-functions-to-static)
+bool 
SSLContextService::addServerCertificatesFromSystemStoreToSSLContext(SSL_CTX* 
ctx) const {  // NOLINT(readability-convert-member-functions-to-static)
 #ifdef WIN32
   X509_STORE* ssl_store = SSL_CTX_get_cert_store(ctx);
   if (!ssl_store) {
@@ -323,7 +323,7 @@ bool 
SSLContextServiceImpl::addServerCertificatesFromSystemStoreToSSLContext(SSL
 }
 
 #ifdef WIN32
-bool SSLContextServiceImpl::findServerCertificate(ServerCertCallback cb) const 
{
+bool SSLContextService::findServerCertificate(ServerCertCallback cb) const {
   utils::tls::WindowsCertStore 
cert_store(utils::tls::WindowsCertStoreLocation{cert_store_location_}, 
server_cert_store_);
   if (auto error = cert_store.error()) {
     logger_->log_error("Could not open system certificate store {}/{} (server 
certificates): {}", cert_store_location_, server_cert_store_, error.message());
@@ -343,7 +343,7 @@ bool 
SSLContextServiceImpl::findServerCertificate(ServerCertCallback cb) const {
 #endif
 
 #ifdef WIN32
-bool SSLContextServiceImpl::useServerCertificate(PCCERT_CONTEXT certificate, 
ServerCertCallback cb) const {
+bool SSLContextService::useServerCertificate(PCCERT_CONTEXT certificate, 
ServerCertCallback cb) const {
   utils::tls::X509_unique_ptr x509_cert = 
utils::tls::convertWindowsCertificate(certificate);
   if (!x509_cert) {
     logger_->log_error("Failed to convert system store server certificate to 
X.509 format");
@@ -359,7 +359,7 @@ bool 
SSLContextServiceImpl::useServerCertificate(PCCERT_CONTEXT certificate, Ser
  * be returned and it will be up to the caller to determine if this failure is
  * recoverable.
  */
-std::unique_ptr<SSLContext> SSLContextServiceImpl::createSSLContext() {
+std::unique_ptr<SSLContext> SSLContextService::createSSLContext() {
   SSL_library_init();
   const SSL_METHOD *method = nullptr;
 
@@ -380,27 +380,27 @@ std::unique_ptr<SSLContext> 
SSLContextServiceImpl::createSSLContext() {
   return std::make_unique<SSLContext>(ctx);
 }
 
-const std::filesystem::path &SSLContextServiceImpl::getCertificateFile() const 
{
+const std::filesystem::path &SSLContextService::getCertificateFile() const {
   std::lock_guard<std::mutex> lock(initialization_mutex_);
   return certificate_;
 }
 
-const std::string &SSLContextServiceImpl::getPassphrase() const {
+const std::string &SSLContextService::getPassphrase() const {
   std::lock_guard<std::mutex> lock(initialization_mutex_);
   return passphrase_;
 }
 
-const std::filesystem::path &SSLContextServiceImpl::getPrivateKeyFile() const {
+const std::filesystem::path &SSLContextService::getPrivateKeyFile() const {
   std::lock_guard<std::mutex> lock(initialization_mutex_);
   return private_key_;
 }
 
-const std::filesystem::path &SSLContextServiceImpl::getCACertificate() const {
+const std::filesystem::path &SSLContextService::getCACertificate() const {
   std::lock_guard<std::mutex> lock(initialization_mutex_);
   return ca_certificate_;
 }
 
-void SSLContextServiceImpl::onEnable() {
+void SSLContextService::onEnable() {
   std::filesystem::path default_dir;
 
   if (configuration_) {
@@ -505,11 +505,11 @@ void SSLContextServiceImpl::onEnable() {
   verifyCertificateExpiration();
 }
 
-void SSLContextServiceImpl::initializeProperties() {
+void SSLContextService::initializeProperties() {
   setSupportedProperties(Properties);
 }
 
-void SSLContextServiceImpl::verifyCertificateExpiration() {
+void SSLContextService::verifyCertificateExpiration() {
   auto verify = [&] (const std::filesystem::path& cert_file, const 
utils::tls::X509_unique_ptr& cert) {
     if (auto end_date = utils::tls::getCertificateExpiration(cert)) {
       std::string end_date_str = utils::timeutils::getTimeStr(*end_date);
@@ -594,6 +594,6 @@ void SSLContextServiceImpl::verifyCertificateExpiration() {
 #endif
 }
 
-REGISTER_RESOURCE_IMPLEMENTATION(SSLContextServiceImpl, "SSLContextService", 
ControllerService);
+REGISTER_RESOURCE_IMPLEMENTATION(SSLContextService, "SSLContextService", 
ControllerService);
 
 }  // namespace org::apache::nifi::minifi::controllers
diff --git a/libminifi/src/core/logging/alert/AlertSink.cpp 
b/libminifi/src/core/logging/alert/AlertSink.cpp
index 89508b220..86745e88e 100644
--- a/libminifi/src/core/logging/alert/AlertSink.cpp
+++ b/libminifi/src/core/logging/alert/AlertSink.cpp
@@ -21,7 +21,7 @@
 #include "http/BaseHTTPClient.h"
 #include "utils/Hash.h"
 #include "core/logging/Utils.h"
-#include "controllers/SSLContextService.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 
 #include "rapidjson/rapidjson.h"
 #include "rapidjson/document.h"
@@ -103,7 +103,7 @@ void 
AlertSink::initialize(core::controller::ControllerServiceProvider* controll
       return;
     }
     if (auto service = 
controller->getControllerService(config_.ssl_service_name.value())) {
-      if (auto ssl_service = 
std::dynamic_pointer_cast<controllers::SSLContextService>(service)) {
+      if (auto ssl_service = 
std::dynamic_pointer_cast<controllers::SSLContextServiceInterface>(service)) {
         services->ssl_service = ssl_service;
       } else {
         logger_->log_error("Service '{}' is not an SSLContextService", 
config_.ssl_service_name.value());
diff --git a/libminifi/src/core/state/nodes/AgentInformation.cpp 
b/libminifi/src/core/state/nodes/AgentInformation.cpp
index b9e2d8cd1..6b8c8424d 100644
--- a/libminifi/src/core/state/nodes/AgentInformation.cpp
+++ b/libminifi/src/core/state/nodes/AgentInformation.cpp
@@ -76,7 +76,7 @@ void ComponentManifest::serializeClassDescription(const 
std::vector<ClassDescrip
             utils::string::replaceAll(typeClazz, "::", ".");
             allowed_type.children.push_back({.name = "type", .value = 
typeClazz});
             allowed_type.children.push_back({.name = "group", .value = 
GROUP_STR});
-            allowed_type.children.push_back({.name = "artifact", .value = 
core::ClassLoader::getDefaultClassLoader().getGroupForClass(class_name).value_or("")});
+            allowed_type.children.push_back({.name = "artifact", .value = 
core::ClassLoader::getDefaultClassLoader().getGroupForClass(class_name).value_or("minifi-system")});
           }
           child.children.push_back(allowed_type);
         }
@@ -143,6 +143,17 @@ void ComponentManifest::serializeClassDescription(const 
std::vector<ClassDescrip
     desc.children.push_back({.name = "supportsDynamicRelationships", .value = 
group.supports_dynamic_relationships_});
     desc.children.push_back({.name = "supportsDynamicProperties", .value = 
group.supports_dynamic_properties_});
     desc.children.push_back({.name = "type", .value = group.full_name_});
+    if (!group.api_implementations.empty()) {
+      SerializedResponseNode provided_api_impls{.name = 
"providedApiImplementations", .array = true};
+      for (const auto& api_implementation : group.api_implementations) {
+        SerializedResponseNode child{.name = 
std::string(api_implementation.type)};
+        child.children.push_back({.name = "artifact", .value = 
std::string(api_implementation.artifact)});
+        child.children.push_back({.name = "group", .value = 
std::string(api_implementation.group)});
+        child.children.push_back({.name = "type", .value = 
std::string(api_implementation.type)});
+        provided_api_impls.children.push_back(child);
+      }
+      desc.children.push_back(provided_api_impls);
+    }
 
     type.children.push_back(desc);
   }
diff --git a/libminifi/test/integration/ControllerServiceIntegrationTests.cpp 
b/libminifi/test/integration/ControllerServiceIntegrationTests.cpp
index 99ef66062..e6aed9cbf 100644
--- a/libminifi/test/integration/ControllerServiceIntegrationTests.cpp
+++ b/libminifi/test/integration/ControllerServiceIntegrationTests.cpp
@@ -21,23 +21,23 @@
 #include <chrono>
 #include <memory>
 #include <string>
-#include <utility>
 #include <thread>
+#include <utility>
 #include <vector>
 
-#include "core/controller/ControllerServiceNodeMap.h"
-#include "core/controller/StandardControllerServiceProvider.h"
+#include "FlowController.h"
 #include "controllers/SSLContextService.h"
 #include "core/ProcessGroup.h"
 #include "core/Resource.h"
+#include "core/controller/ControllerServiceNodeMap.h"
+#include "core/controller/StandardControllerServiceProvider.h"
 #include "core/yaml/YamlConfiguration.h"
-#include "FlowController.h"
+#include "integration/IntegrationBase.h"
 #include "properties/Configure.h"
+#include "unit/Catch.h"
 #include "unit/MockClasses.h"
 #include "unit/ProvenanceTestHelper.h"
-#include "integration/IntegrationBase.h"
 #include "unit/TestUtils.h"
-#include "unit/Catch.h"
 
 namespace org::apache::nifi::minifi::test {
 
@@ -106,7 +106,7 @@ TEST_CASE("ControllerServiceIntegrationTests", 
"[controller]") {
   core::controller::ControllerServiceNode* notexistNode = 
pg->findControllerService("MockItLikeItsWrong");
   REQUIRE(notexistNode == nullptr);
 
-  std::shared_ptr<minifi::controllers::SSLContextService> ssl_client;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> ssl_client;
   {
     std::lock_guard<std::mutex> lock(control_mutex);
     controller->load();
@@ -115,7 +115,7 @@ TEST_CASE("ControllerServiceIntegrationTests", 
"[controller]") {
     REQUIRE(ssl_client_node != nullptr);
     ssl_client_node->enable();
     REQUIRE(ssl_client_node->getControllerServiceImplementation() != nullptr);
-    ssl_client = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(ssl_client_node->getControllerServiceImplementation());
+    ssl_client = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(ssl_client_node->getControllerServiceImplementation());
   }
   REQUIRE(!ssl_client->getCACertificate().empty());
   // now let's disable one of the controller services.
diff --git a/libminifi/test/integration/HTTPSiteToSiteTests.cpp 
b/libminifi/test/integration/HTTPSiteToSiteTests.cpp
index 969e4adf4..b5ef811ae 100644
--- a/libminifi/test/integration/HTTPSiteToSiteTests.cpp
+++ b/libminifi/test/integration/HTTPSiteToSiteTests.cpp
@@ -48,7 +48,7 @@ class SiteToSiteTestHarness : public HTTPIntegrationBase {
     
LogTestController::getInstance().setTrace<minifi::sitetosite::HttpSiteToSiteClient>();
     
LogTestController::getInstance().setTrace<minifi::sitetosite::SiteToSiteClient>();
     LogTestController::getInstance().setTrace<minifi::http::HTTPClient>();
-    
LogTestController::getInstance().setTrace<minifi::controllers::SSLContextService>();
+    
LogTestController::getInstance().setTrace<minifi::controllers::SSLContextServiceInterface>();
     LogTestController::getInstance().setInfo<minifi::FlowController>();
     LogTestController::getInstance().setDebug<core::ConfigurableComponent>();
     
LogTestController::getInstance().setTrace<minifi::http::HttpStreamingCallback>();
diff --git a/libminifi/test/integration/SiteToSiteRestTest.cpp 
b/libminifi/test/integration/SiteToSiteRestTest.cpp
index 99b4c4b21..bc64b7bcf 100644
--- a/libminifi/test/integration/SiteToSiteRestTest.cpp
+++ b/libminifi/test/integration/SiteToSiteRestTest.cpp
@@ -16,17 +16,18 @@
  * limitations under the License.
  */
 #include <cstdio>
-#include <string>
 #include <iostream>
-#include "processors/InvokeHTTP.h"
-#include "unit/TestBase.h"
-#include "core/logging/Logger.h"
-#include "FlowController.h"
+#include <string>
+
 #include "CivetServer.h"
+#include "FlowController.h"
 #include "RemoteProcessorGroupPort.h"
-#include "core/ConfigurableComponentImpl.h"
 #include "controllers/SSLContextService.h"
+#include "core/ConfigurableComponentImpl.h"
+#include "core/logging/Logger.h"
 #include "integration/HTTPIntegrationBase.h"
+#include "processors/InvokeHTTP.h"
+#include "unit/TestBase.h"
 #include "unit/TestUtils.h"
 
 namespace org::apache::nifi::minifi::test {
@@ -69,7 +70,7 @@ class SiteToSiteTestHarness : public HTTPIntegrationBase {
   void testSetup() override {
     
LogTestController::getInstance().setTrace<minifi::RemoteProcessorGroupPort>();
     LogTestController::getInstance().setDebug<minifi::http::HTTPClient>();
-    
LogTestController::getInstance().setTrace<minifi::controllers::SSLContextService>();
+    
LogTestController::getInstance().setTrace<minifi::controllers::SSLContextServiceInterface>();
     LogTestController::getInstance().setInfo<minifi::FlowController>();
     LogTestController::getInstance().setDebug<core::ConfigurableComponent>();
 
diff --git a/libminifi/test/integration/TimeoutHTTPSiteToSiteTests.cpp 
b/libminifi/test/integration/TimeoutHTTPSiteToSiteTests.cpp
index 7cf5ad12d..b5e08bcbb 100644
--- a/libminifi/test/integration/TimeoutHTTPSiteToSiteTests.cpp
+++ b/libminifi/test/integration/TimeoutHTTPSiteToSiteTests.cpp
@@ -49,7 +49,7 @@ class SiteToSiteTestHarness : public HTTPIntegrationBase {
     
LogTestController::getInstance().setTrace<minifi::sitetosite::HttpSiteToSiteClient>();
     
LogTestController::getInstance().setTrace<minifi::sitetosite::SiteToSiteClient>();
     LogTestController::getInstance().setTrace<minifi::http::HTTPClient>();
-    
LogTestController::getInstance().setTrace<minifi::controllers::SSLContextService>();
+    
LogTestController::getInstance().setTrace<minifi::controllers::SSLContextServiceInterface>();
     LogTestController::getInstance().setInfo<minifi::FlowController>();
     LogTestController::getInstance().setDebug<core::ConfigurableComponent>();
     
LogTestController::getInstance().setTrace<minifi::http::HttpStreamingCallback>();
diff --git a/libminifi/test/unit/NetUtilsTest.cpp 
b/libminifi/test/unit/NetUtilsTest.cpp
index fe6fbc848..3d2cfd9d4 100644
--- a/libminifi/test/unit/NetUtilsTest.cpp
+++ b/libminifi/test/unit/NetUtilsTest.cpp
@@ -18,13 +18,13 @@
 
 #include <string>
 
-#include "unit/TestBase.h"
-#include "unit/Catch.h"
-#include "utils/net/DNS.h"
-#include "utils/net/AsioSocketUtils.h"
-#include "utils/StringUtils.h"
 #include "controllers/SSLContextService.h"
+#include "unit/Catch.h"
+#include "unit/TestBase.h"
 #include "unit/TestUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/net/AsioSocketUtils.h"
+#include "utils/net/DNS.h"
 
 namespace utils = org::apache::nifi::minifi::utils;
 namespace net = utils::net;
@@ -64,34 +64,34 @@ TEST_CASE("utils::net::getSslContext") {
   auto plan = controller.createPlan();
 
   auto ssl_context_node = plan->addController("SSLContextService", 
"ssl_context_service");
-  auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(ssl_context_node->getControllerServiceImplementation());
+  auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(ssl_context_node->getControllerServiceImplementation());
 
   const std::filesystem::path cert_dir = 
minifi::utils::file::FileUtils::get_executable_dir() / "resources";
 
-  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::CACertificate.name,
 (cert_dir / "ca_A.crt").string()));
+  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::CACertificate.name,
 (cert_dir / "ca_A.crt").string()));
 
   SECTION("Secure") {
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::PrivateKey.name,
 (cert_dir / "alice.key").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::PrivateKey.name,
 (cert_dir / "alice.key").string()));
   }
   SECTION("Secure empty pass") {
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::PrivateKey.name,
 (cert_dir / "alice.key").string()));
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::Passphrase.name,
 (cert_dir / "empty_pass").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::PrivateKey.name,
 (cert_dir / "alice.key").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::Passphrase.name,
 (cert_dir / "empty_pass").string()));
   }
   SECTION("Secure with file pass") {
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::PrivateKey.name,
 (cert_dir / "alice_encrypted.key").string()));
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::Passphrase.name,
 (cert_dir / "alice_encryption_pass").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::PrivateKey.name,
 (cert_dir / "alice_encrypted.key").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::Passphrase.name,
 (cert_dir / "alice_encryption_pass").string()));
   }
   SECTION("Secure with pass") {
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::PrivateKey.name,
 (cert_dir / "alice_encrypted.key").string()));
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::Passphrase.name,
 "VsVTmHBzixyA9UfTCttRYXus1oMpIxO6jmDXrNrOp5w"));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::PrivateKey.name,
 (cert_dir / "alice_encrypted.key").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::Passphrase.name,
 "VsVTmHBzixyA9UfTCttRYXus1oMpIxO6jmDXrNrOp5w"));
   }
   SECTION("Secure with common cert and key file") {
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::ClientCertificate.name,
 (cert_dir / "alice_by_A_with_key.pem").string()));
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::CACertificate.name,
 (cert_dir / "alice_by_A_with_key.pem").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::ClientCertificate.name,
 (cert_dir / "alice_by_A_with_key.pem").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::CACertificate.name,
 (cert_dir / "alice_by_A_with_key.pem").string()));
   }
   REQUIRE_NOTHROW(plan->finalize());
   auto ssl_context = utils::net::getSslContext(*ssl_context_service);
@@ -105,13 +105,13 @@ TEST_CASE("utils::net::getSslContext passphrase 
problems") {
   auto plan = controller.createPlan();
 
   auto ssl_context_node = plan->addController("SSLContextService", 
"ssl_context_service");
-  auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(ssl_context_node->getControllerServiceImplementation());
+  auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(ssl_context_node->getControllerServiceImplementation());
 
   const std::filesystem::path cert_dir = 
minifi::utils::file::FileUtils::get_executable_dir() / "resources";
 
-  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::CACertificate.name,
 (cert_dir / "ca_A.crt").string()));
-  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
-  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::PrivateKey.name,
 (cert_dir / "alice_encrypted.key").string()));
+  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::CACertificate.name,
 (cert_dir / "ca_A.crt").string()));
+  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
+  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::PrivateKey.name,
 (cert_dir / "alice_encrypted.key").string()));
 
   SECTION("Missing passphrase") {
     REQUIRE_NOTHROW(plan->finalize());
@@ -119,13 +119,13 @@ TEST_CASE("utils::net::getSslContext passphrase 
problems") {
   }
 
   SECTION("Invalid passphrase") {
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::Passphrase.name,
 "not_the_correct_passphrase"));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::Passphrase.name,
 "not_the_correct_passphrase"));
     REQUIRE_NOTHROW(plan->finalize());
     REQUIRE_THROWS_WITH(utils::net::getSslContext(*ssl_context_service), 
"use_private_key_file: bad decrypt (Provider routines)");
   }
 
   SECTION("Invalid passphrase file") {
-    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::Passphrase.name,
 (cert_dir / "alice_by_B.pem").string()));
+    
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::Passphrase.name,
 (cert_dir / "alice_by_B.pem").string()));
     REQUIRE_NOTHROW(plan->finalize());
     REQUIRE_THROWS_WITH(utils::net::getSslContext(*ssl_context_service), 
"use_private_key_file: bad decrypt (Provider routines)");
   }
@@ -136,12 +136,12 @@ TEST_CASE("utils::net::getSslContext missing CA") {
   auto plan = controller.createPlan();
 
   auto ssl_context_node = plan->addController("SSLContextService", 
"ssl_context_service");
-  auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextService>(ssl_context_node->getControllerServiceImplementation());
+  auto ssl_context_service = 
std::dynamic_pointer_cast<minifi::controllers::SSLContextServiceInterface>(ssl_context_node->getControllerServiceImplementation());
 
   const std::filesystem::path cert_dir = 
minifi::utils::file::FileUtils::get_executable_dir() / "resources";
 
-  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
-  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextServiceImpl::PrivateKey.name,
 (cert_dir / "alice.key").string()));
+  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::ClientCertificate.name,
 (cert_dir / "alice_by_A.pem").string()));
+  
REQUIRE(ssl_context_service->setProperty(minifi::controllers::SSLContextService::PrivateKey.name,
 (cert_dir / "alice.key").string()));
 
   REQUIRE_NOTHROW(plan->finalize());
   auto ssl_context = utils::net::getSslContext(*ssl_context_service);
diff --git a/minifi-api/include/minifi-cpp/agent/agent_docs.h 
b/minifi-api/include/minifi-cpp/agent/agent_docs.h
index 21106cec1..bccd7160c 100644
--- a/minifi-api/include/minifi-cpp/agent/agent_docs.h
+++ b/minifi-api/include/minifi-cpp/agent/agent_docs.h
@@ -24,6 +24,7 @@
 #include "minifi-cpp/core/Annotation.h"
 #include "minifi-cpp/core/DynamicProperty.h"
 #include "minifi-cpp/core/OutputAttributeDefinition.h"
+#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
 #include "minifi-cpp/core/Property.h"
 #include "minifi-cpp/core/Relationship.h"
 #include "minifi-cpp/core/RelationshipDefinition.h"
@@ -43,6 +44,7 @@ struct ClassDescription {
   std::span<const core::DynamicProperty> dynamic_properties_{};
   std::vector<core::Relationship> class_relationships_{};
   std::span<const core::OutputAttributeReference> output_attributes_{};
+  std::span<const core::ControllerServiceApiDefinition> api_implementations{};
   bool supports_dynamic_properties_ = false;
   bool supports_dynamic_relationships_ = false;
   std::string inputRequirement_{};
diff --git a/minifi-api/include/minifi-cpp/controllers/RecordSetReader.h 
b/minifi-api/include/minifi-cpp/controllers/RecordSetReader.h
index 1c28b4f8b..e5d207da2 100644
--- a/minifi-api/include/minifi-cpp/controllers/RecordSetReader.h
+++ b/minifi-api/include/minifi-cpp/controllers/RecordSetReader.h
@@ -30,6 +30,12 @@ namespace org::apache::nifi::minifi::core {
 
 class RecordSetReader : public virtual controller::ControllerService {
  public:
+  static constexpr auto ProvidesApi = core::ControllerServiceApiDefinition{
+    .artifact = "minifi-system",
+    .group = "org.apache.nifi.minifi",
+    .type = "org.apache.nifi.minifi.core.RecordSetReader",
+  };
+
   virtual nonstd::expected<RecordSet, std::error_code> read(const 
std::shared_ptr<FlowFile>& flow_file, ProcessSession& session) = 0;
 };
 
diff --git a/minifi-api/include/minifi-cpp/controllers/RecordSetWriter.h 
b/minifi-api/include/minifi-cpp/controllers/RecordSetWriter.h
index 65eecb5b5..e895f64f3 100644
--- a/minifi-api/include/minifi-cpp/controllers/RecordSetWriter.h
+++ b/minifi-api/include/minifi-cpp/controllers/RecordSetWriter.h
@@ -18,6 +18,7 @@
 
 #include "minifi-cpp/core/controller/ControllerService.h"
 
+#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
 #include "minifi-cpp/core/FlowFile.h"
 #include "minifi-cpp/core/ProcessSession.h"
 #include "minifi-cpp/core/Record.h"
@@ -26,6 +27,12 @@ namespace org::apache::nifi::minifi::core {
 
 class RecordSetWriter : public virtual controller::ControllerService {
  public:
+  static constexpr auto ProvidesApi = core::ControllerServiceApiDefinition{
+    .artifact = "minifi-system",
+    .group = "org.apache.nifi.minifi",
+    .type = "org.apache.nifi.minifi.core.RecordSetWriter",
+  };
+
   virtual void write(const RecordSet& record_set, const 
std::shared_ptr<FlowFile>& flow_file, ProcessSession& session) = 0;
 };
 
diff --git a/minifi-api/include/minifi-cpp/controllers/SSLContextService.h 
b/minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h
similarity index 83%
rename from minifi-api/include/minifi-cpp/controllers/SSLContextService.h
rename to minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h
index f16ef935e..01877c6c4 100644
--- a/minifi-api/include/minifi-cpp/controllers/SSLContextService.h
+++ b/minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h
@@ -21,6 +21,7 @@
 #include <string>
 #include <utility>
 
+#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
 #include "minifi-cpp/core/controller/ControllerService.h"
 
 namespace org::apache::nifi::minifi::controllers {
@@ -33,8 +34,14 @@ namespace org::apache::nifi::minifi::controllers {
  * Justification: Abstracts SSL support out of processors into a
  * configurable controller service.
  */
-class SSLContextService : public virtual core::controller::ControllerService {
+class SSLContextServiceInterface : public virtual 
core::controller::ControllerService {
  public:
+  static constexpr auto ProvidesApi = core::ControllerServiceApiDefinition{
+    .artifact = "minifi-system",
+    .group = "org.apache.nifi.minifi",
+    .type = "org.apache.nifi.minifi.controllers.SSLContextServiceInterface",
+  };
+
   virtual const std::filesystem::path& getCertificateFile() const = 0;
   virtual const std::string& getPassphrase() const = 0;
   virtual const std::filesystem::path& getPrivateKeyFile() const = 0;
@@ -47,4 +54,5 @@ class SSLContextService : public virtual 
core::controller::ControllerService {
   virtual bool configure_ssl_context(void* ssl_ctx) = 0;
 };
 
+
 }  // namespace org::apache::nifi::minifi::controllers
diff --git a/extension-utils/include/controllers/SSLContextService.h 
b/minifi-api/include/minifi-cpp/core/ControllerServiceApiDefinition.h
similarity index 70%
rename from extension-utils/include/controllers/SSLContextService.h
rename to minifi-api/include/minifi-cpp/core/ControllerServiceApiDefinition.h
index e399a734a..172253569 100644
--- a/extension-utils/include/controllers/SSLContextService.h
+++ b/minifi-api/include/minifi-cpp/core/ControllerServiceApiDefinition.h
@@ -1,5 +1,5 @@
 /**
- * Licensed to the Apache Software Foundation (ASF) under one or more
+* Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
  * The ASF licenses this file to You under the Apache License, Version 2.0
@@ -16,4 +16,14 @@
  */
 #pragma once
 
-#include "minifi-cpp/controllers/SSLContextService.h"
\ No newline at end of file
+#include <string_view>
+
+namespace org::apache::nifi::minifi::core {
+
+struct ControllerServiceApiDefinition {
+  std::string_view artifact;
+  std::string_view group;
+  std::string_view type;
+};
+
+}  // namespace org::apache::nifi::minifi::core
diff --git a/utils/include/agent/agent_docs.h b/utils/include/agent/agent_docs.h
index a3282d2fd..09142be4e 100644
--- a/utils/include/agent/agent_docs.h
+++ b/utils/include/agent/agent_docs.h
@@ -70,7 +70,8 @@ void AgentDocs::createClassDescription(const std::string& 
group, const std::stri
         .full_name_ = detail::classNameWithDots<Class>(),
         .description_ = Class::Description,
         .class_properties_ = detail::toVector(Class::Properties),
-        .supports_dynamic_properties_ = Class::SupportsDynamicProperties,
+        .api_implementations = Class::ImplementsApis,
+        .supports_dynamic_properties_ = Class::SupportsDynamicProperties
     });
   } else if constexpr (Type == ResourceType::InternalResource) {
     components.other_components_.push_back(ClassDescription{
diff --git a/utils/include/core/controller/ControllerService.h 
b/utils/include/core/controller/ControllerService.h
index 25ecf7a82..bd0432802 100644
--- a/utils/include/core/controller/ControllerService.h
+++ b/utils/include/core/controller/ControllerService.h
@@ -27,6 +27,7 @@
 #include "core/ConfigurableComponentImpl.h"
 #include "core/Connectable.h"
 #include "minifi-cpp/core/controller/ControllerService.h"
+#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
 
 #define ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_CONTROLLER_SERVICES \
   bool supportsDynamicProperties() const override { return 
SupportsDynamicProperties; }
@@ -105,6 +106,9 @@ class ControllerServiceImpl : public 
ConfigurableComponentImpl, public Connectab
     linked_services_ = services;
   }
 
+
+  static constexpr auto ImplementsApis = 
std::array<ControllerServiceApiDefinition, 0>{};
+
  protected:
   std::vector<std::shared_ptr<controller::ControllerService> > 
linked_services_;
   std::shared_ptr<Configure> configuration_;
diff --git a/utils/include/http/BaseHTTPClient.h 
b/utils/include/http/BaseHTTPClient.h
index 016abb12b..a3389571a 100644
--- a/utils/include/http/BaseHTTPClient.h
+++ b/utils/include/http/BaseHTTPClient.h
@@ -22,11 +22,11 @@
 #include <memory>
 #include <optional>
 #include <string>
-#include <vector>
 #include <utility>
+#include <vector>
 
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 #include "utils/ByteArrayCallback.h"
-#include "minifi-cpp/controllers/SSLContextService.h"
 #include "utils/gsl.h"
 
 namespace org::apache::nifi::minifi::http {
@@ -191,7 +191,7 @@ class BaseHTTPClient {
 
   virtual void setVerbose(bool use_stderr) = 0;
 
-  virtual void initialize(HttpRequestMethod method, std::string url, 
std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service) = 
0;
+  virtual void initialize(HttpRequestMethod method, std::string url, 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service) = 0;
 
   virtual void setConnectionTimeout(std::chrono::milliseconds timeout) = 0;
 
diff --git a/utils/include/http/HTTPClient.h b/utils/include/http/HTTPClient.h
index e6dc56d61..eb9e7f057 100644
--- a/utils/include/http/HTTPClient.h
+++ b/utils/include/http/HTTPClient.h
@@ -29,6 +29,7 @@
 #include <curl/curl.h>
 #endif
 #include <curl/easy.h>
+
 #include <chrono>
 #include <limits>
 #include <map>
@@ -40,11 +41,11 @@
 #include <utility>
 #include <vector>
 
-#include "utils/ByteArrayCallback.h"
-#include "minifi-cpp/controllers/SSLContextService.h"
+#include "core/Connectable.h"
 #include "core/logging/Logger.h"
 #include "core/logging/LoggerFactory.h"
-#include "core/Connectable.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
+#include "utils/ByteArrayCallback.h"
 
 namespace org::apache::nifi::minifi::http {
 
@@ -76,7 +77,7 @@ class HTTPClient : public BaseHTTPClient, public 
core::ConnectableImpl {
   HTTPClient(const HTTPClient&) = delete;
   HTTPClient& operator=(const HTTPClient&) = delete;
 
-  explicit HTTPClient(std::string url, 
std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service = 
nullptr);
+  explicit HTTPClient(std::string url, 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service = nullptr);
 
   ~HTTPClient() override;
 
@@ -92,7 +93,7 @@ class HTTPClient : public BaseHTTPClient, public 
core::ConnectableImpl {
 
   void forceClose();
 
-  void initialize(http::HttpRequestMethod method, std::string url, 
std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service) 
override;
+  void initialize(http::HttpRequestMethod method, std::string url, 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service) override;
 
   void setConnectionTimeout(std::chrono::milliseconds timeout) override;
 
@@ -216,7 +217,7 @@ class HTTPClient : public BaseHTTPClient, public 
core::ConnectableImpl {
   static CURLcode configure_ssl_context(CURL* /*curl*/, void *ctx, void 
*param) {
     gsl_Expects(ctx);
     gsl_Expects(param);
-    auto& ssl_context_service = 
*static_cast<minifi::controllers::SSLContextService*>(param);
+    auto& ssl_context_service = 
*static_cast<minifi::controllers::SSLContextServiceInterface*>(param);
     if (!ssl_context_service.configure_ssl_context(ctx)) {
       return CURLE_FAILED_INIT;
     }
@@ -229,7 +230,7 @@ class HTTPClient : public BaseHTTPClient, public 
core::ConnectableImpl {
 
   HTTPReadCallback content_{std::numeric_limits<size_t>::max()};
 
-  std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service_;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service_;
   std::string url_;
   std::optional<http::HttpRequestMethod> method_;
 
diff --git a/utils/include/utils/net/AsioSocketUtils.h 
b/utils/include/utils/net/AsioSocketUtils.h
index f8df7e959..b052fc072 100644
--- a/utils/include/utils/net/AsioSocketUtils.h
+++ b/utils/include/utils/net/AsioSocketUtils.h
@@ -21,22 +21,21 @@
 #include <ifaddrs.h>
 #endif
 
+#include <memory>
 #include <string>
-#include <utility>
 #include <tuple>
-#include <memory>
-
-#include "asio/ssl.hpp"
-#include "asio/ip/tcp.hpp"
+#include <utility>
 
 #include "AsioCoro.h"
-#include "utils/Hash.h"
-#include "utils/StringUtils.h"  // for string <=> on libc++
-#include "minifi-cpp/controllers/SSLContextService.h"
+#include "asio/ip/tcp.hpp"
+#include "asio/ssl.hpp"
+#include "core/logging/LoggerFactory.h"
 #include "io/BaseStream.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 #include "utils/Deleters.h"
+#include "utils/Hash.h"
+#include "utils/StringUtils.h"  // for string <=> on libc++
 #include "utils/net/Socket.h"
-#include "core/logging/LoggerFactory.h"
 
 namespace org::apache::nifi::minifi::utils::net {
 
@@ -73,12 +72,12 @@ template<>
 asio::awaitable<std::tuple<std::error_code>> handshake(SslSocket& socket, 
asio::steady_timer::duration);
 
 
-asio::ssl::context getSslContext(const controllers::SSLContextService& 
ssl_context_service, asio::ssl::context::method ssl_context_method = 
asio::ssl::context::tls_client);
+asio::ssl::context getSslContext(const 
controllers::SSLContextServiceInterface& ssl_context_service, 
asio::ssl::context::method ssl_context_method = asio::ssl::context::tls_client);
 
 struct SocketData {
   std::string host = "localhost";
   int port = -1;
-  std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service;
+  std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service;
 };
 
 class AsioSocketConnection : public io::BaseStreamImpl {
diff --git a/utils/src/http/HTTPClient.cpp b/utils/src/http/HTTPClient.cpp
index e82b812b4..a689d8e3d 100644
--- a/utils/src/http/HTTPClient.cpp
+++ b/utils/src/http/HTTPClient.cpp
@@ -40,7 +40,7 @@ using namespace std::literals::chrono_literals;
 
 namespace org::apache::nifi::minifi::http {
 
-HTTPClient::HTTPClient(std::string url, 
std::shared_ptr<minifi::controllers::SSLContextService>  ssl_context_service)
+HTTPClient::HTTPClient(std::string url, 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface>  
ssl_context_service)
     : core::ConnectableImpl("HTTPClient"),
       ssl_context_service_(std::move(ssl_context_service)),
       url_(std::move(url)) {
@@ -115,7 +115,7 @@ bool isSecure(const std::string& url) {
 }
 }  // namespace
 
-void HTTPClient::initialize(http::HttpRequestMethod method, std::string url, 
std::shared_ptr<minifi::controllers::SSLContextService> ssl_context_service) {
+void HTTPClient::initialize(http::HttpRequestMethod method, std::string url, 
std::shared_ptr<minifi::controllers::SSLContextServiceInterface> 
ssl_context_service) {
   set_request_method(method);
   if (ssl_context_service) {
     ssl_context_service_ = std::move(ssl_context_service);
diff --git a/utils/src/utils/net/AsioSocketUtils.cpp 
b/utils/src/utils/net/AsioSocketUtils.cpp
index 632b98eed..36e7fd0af 100644
--- a/utils/src/utils/net/AsioSocketUtils.cpp
+++ b/utils/src/utils/net/AsioSocketUtils.cpp
@@ -16,10 +16,10 @@
  */
 
 #include "utils/net/AsioSocketUtils.h"
-#include "minifi-cpp/controllers/SSLContextService.h"
-#include "io/AsioStream.h"
 
 #include "asio/connect.hpp"
+#include "io/AsioStream.h"
+#include "minifi-cpp/controllers/SSLContextServiceInterface.h"
 
 namespace org::apache::nifi::minifi::utils::net {
 
@@ -33,7 +33,7 @@ asio::awaitable<std::tuple<std::error_code>> 
handshake(SslSocket& socket, asio::
   co_return co_await 
asyncOperationWithTimeout(socket.async_handshake(HandshakeType::client, 
use_nothrow_awaitable), timeout_duration);  // NOLINT
 }
 
-asio::ssl::context getSslContext(const controllers::SSLContextService& 
ssl_context_service, asio::ssl::context::method ssl_context_method) {
+asio::ssl::context getSslContext(const 
controllers::SSLContextServiceInterface& ssl_context_service, 
asio::ssl::context::method ssl_context_method) {
   asio::ssl::context ssl_context(ssl_context_method);
   ssl_context.set_options(MINIFI_SSL_OPTIONS);
   if (const auto& ca_cert = ssl_context_service.getCACertificate(); 
!ca_cert.empty())

Reply via email to