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

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

commit 1b1a774473620d08374d59c8cba3b1fd6bf5c931
Author: Martin Zink <[email protected]>
AuthorDate: Thu Feb 12 16:51:46 2026 +0100

    MINIFICPP-2708 Controller Service C API
    
    Built upon ongoing #2065 #2098 and #2105 PR-s
    
    Closes #2096
    
    Signed-off-by: Martin Zink <[email protected]>
---
 Extensions.md                                      |   4 +-
 core-framework/include/agent/agent_docs.h          |  13 +-
 .../core/controller/ControllerServiceBase.h        |   6 +-
 .../core/controller/ControllerServiceFactoryImpl.h |   4 +-
 core-framework/include/http/HTTPClient.h           |   1 +
 core-framework/include/utils/ThreadPool.h          |   2 +-
 extensions/ExtensionInitializer.cpp                |   4 +-
 .../aws/tests/MultipartUploadStateStorageTest.cpp  |   2 +-
 .../llamacpp/processors/ExtensionInitializer.cpp   |   2 +
 extensions/opencv/OpenCVLoader.cpp                 |   4 +-
 .../python/pythonlibloader/PythonLibLoader.cpp     |   4 +-
 extensions/python/pythonloader/PyProcLoader.cpp    |   4 +-
 extensions/sftp/SFTPLoader.cpp                     |   4 +-
 .../controllers/NetworkPrioritizerService.h        |   2 +-
 .../include/core/controller/ControllerService.h    |   9 +-
 libminifi/include/utils/CControllerService.h       | 110 ++++++++++++++++
 libminifi/include/utils/CProcessor.h               |   9 +-
 libminifi/src/controllers/SSLContextService.cpp    |   2 +-
 libminifi/src/minifi-c.cpp                         | 138 +++++++++++++++++++--
 libminifi/src/properties/Properties.cpp            |   1 +
 libminifi/test/libtest/integration/HTTPHandlers.h  |  13 +-
 .../test/libtest/unit/ControllerServiceUtils.h     |   2 +-
 .../test/unit/NetworkPrioritizerServiceTests.cpp   |   2 +-
 .../minifi-cpp/core}/ControllerServiceMetadata.h   |   6 +-
 minifi-api/include/minifi-c/minifi-c.h             |  35 ++++++
 minifi-api/include/minifi-cpp/agent/agent_docs.h   |   4 +-
 .../minifi-cpp/controllers/RecordSetReader.h       |   4 +-
 .../minifi-cpp/controllers/RecordSetWriter.h       |   4 +-
 .../controllers/SSLContextServiceInterface.h       |   6 +-
 ...trollerServiceApi.h => ControllerServiceType.h} |   6 +-
 ...inition.h => ControllerServiceTypeDefinition.h} |   2 +-
 .../core/controller/ControllerServiceDescriptor.h  |   1 +
 .../core/controller/ControllerServiceFactory.h     |   5 +-
 .../core/controller/ControllerServiceInterface.h   |  15 ---
 minifi-api/minifi-c-api.def                        |   2 +
 35 files changed, 355 insertions(+), 77 deletions(-)

diff --git a/Extensions.md b/Extensions.md
index 3a82e212f..0dcf4c604 100644
--- a/Extensions.md
+++ b/Extensions.md
@@ -47,7 +47,9 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     .deinit = nullptr,
     .user_data = nullptr,
     .processors_count = 0,
-    .processors_ptr = nullptr
+    .processors_ptr = nullptr,
+    .controller_services_count = 0,
+    .controller_services_ptr = nullptr,
   };
   return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
 }
diff --git a/core-framework/include/agent/agent_docs.h 
b/core-framework/include/agent/agent_docs.h
index 14544f2d6..4c7e25035 100644
--- a/core-framework/include/agent/agent_docs.h
+++ b/core-framework/include/agent/agent_docs.h
@@ -16,18 +16,17 @@
  */
 #pragma once
 
-#include "minifi-cpp/agent/agent_docs.h"
-
 #include <map>
 #include <string>
 #include <utility>
 #include <vector>
 
-#include "utils/StringUtils.h"
 #include "core/ClassName.h"
-#include "minifi-cpp/core/OutputAttribute.h"
-#include "minifi-cpp/core/ControllerServiceApi.h"
+#include "minifi-cpp/agent/agent_docs.h"
+#include "minifi-cpp/core/ControllerServiceType.h"
 #include "minifi-cpp/core/DynamicProperty.h"
+#include "minifi-cpp/core/OutputAttribute.h"
+#include "utils/StringUtils.h"
 
 namespace org::apache::nifi::minifi {
 
@@ -44,8 +43,8 @@ inline auto toVector(std::span<const 
core::OutputAttributeReference> attributes)
   return std::vector<core::OutputAttribute>(attributes.begin(), 
attributes.end());
 }
 
-inline auto toVector(std::span<const core::ControllerServiceApiDefinition> 
apis) {
-  return std::vector<core::ControllerServiceApi>(apis.begin(), apis.end());
+inline auto toVector(std::span<const core::ControllerServiceTypeDefinition> 
apis) {
+  return std::vector<core::ControllerServiceType>(apis.begin(), apis.end());
 }
 
 inline auto toVector(std::span<const core::DynamicPropertyDefinition> 
properties) {
diff --git a/core-framework/include/core/controller/ControllerServiceBase.h 
b/core-framework/include/core/controller/ControllerServiceBase.h
index 2fd22b299..621f48295 100644
--- a/core-framework/include/core/controller/ControllerServiceBase.h
+++ b/core-framework/include/core/controller/ControllerServiceBase.h
@@ -28,8 +28,8 @@
 #include "core/Connectable.h"
 #include "minifi-cpp/core/controller/ControllerServiceApi.h"
 #include "minifi-cpp/core/controller/ControllerServiceInterface.h"
-#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
-#include "minifi-cpp/core/controller/ControllerServiceMetadata.h"
+#include "minifi-cpp/core/ControllerServiceTypeDefinition.h"
+#include "minifi-cpp/core/ControllerServiceMetadata.h"
 
 namespace org::apache::nifi::minifi::core::controller {
 
@@ -95,7 +95,7 @@ class ControllerServiceBase : public ControllerServiceApi {
   }
 
 
-  static constexpr auto ImplementsApis = 
std::array<ControllerServiceApiDefinition, 0>{};
+  static constexpr auto ImplementsApis = 
std::array<ControllerServiceTypeDefinition, 0>{};
 
  protected:
   std::string name_;
diff --git 
a/core-framework/include/core/controller/ControllerServiceFactoryImpl.h 
b/core-framework/include/core/controller/ControllerServiceFactoryImpl.h
index 4060e9d18..a30bd48c6 100644
--- a/core-framework/include/core/controller/ControllerServiceFactoryImpl.h
+++ b/core-framework/include/core/controller/ControllerServiceFactoryImpl.h
@@ -17,10 +17,12 @@
 
 #pragma once
 
-#include <string>
 #include <memory>
+#include <string>
 #include <utility>
+
 #include "core/ClassName.h"
+#include "minifi-cpp/core/ControllerServiceMetadata.h"
 #include "minifi-cpp/core/controller/ControllerServiceFactory.h"
 
 namespace org::apache::nifi::minifi::core::controller {
diff --git a/core-framework/include/http/HTTPClient.h 
b/core-framework/include/http/HTTPClient.h
index 9339a5b21..b27c54df5 100644
--- a/core-framework/include/http/HTTPClient.h
+++ b/core-framework/include/http/HTTPClient.h
@@ -45,6 +45,7 @@
 #include "minifi-cpp/core/logging/Logger.h"
 #include "core/logging/LoggerFactory.h"
 #include "minifi-cpp/controllers/SSLContextServiceInterface.h"
+#include "minifi-cpp/core/PropertyDefinition.h"
 #include "utils/ByteArrayCallback.h"
 
 namespace org::apache::nifi::minifi::http {
diff --git a/core-framework/include/utils/ThreadPool.h 
b/core-framework/include/utils/ThreadPool.h
index f7ecf8cd6..4f2b2af79 100644
--- a/core-framework/include/utils/ThreadPool.h
+++ b/core-framework/include/utils/ThreadPool.h
@@ -135,7 +135,7 @@ class WorkerThread {
  */
 class ThreadPool {
  public:
-  ThreadPool(int max_worker_threads = 2, std::string name = "NamelessPool");
+  explicit ThreadPool(int max_worker_threads = 2, std::string name = 
"NamelessPool");
 
   ThreadPool(const ThreadPool &other) = delete;
   ThreadPool& operator=(const ThreadPool &other) = delete;
diff --git a/extensions/ExtensionInitializer.cpp 
b/extensions/ExtensionInitializer.cpp
index 3caaaeed0..0089b69df 100644
--- a/extensions/ExtensionInitializer.cpp
+++ b/extensions/ExtensionInitializer.cpp
@@ -29,7 +29,9 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     .deinit = nullptr,
     .user_data = nullptr,
     .processors_count = 0,
-    .processors_ptr = nullptr
+    .processors_ptr = nullptr,
+    .controller_services_count = 0,
+    .controller_services_ptr = nullptr,
   };
   return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
 }
diff --git a/extensions/aws/tests/MultipartUploadStateStorageTest.cpp 
b/extensions/aws/tests/MultipartUploadStateStorageTest.cpp
index c791e85c9..fc6f757be 100644
--- a/extensions/aws/tests/MultipartUploadStateStorageTest.cpp
+++ b/extensions/aws/tests/MultipartUploadStateStorageTest.cpp
@@ -32,7 +32,7 @@ class MultipartUploadStateStorageTestFixture {
   MultipartUploadStateStorageTestFixture() {
     
LogTestController::getInstance().setDebug<minifi::aws::s3::MultipartUploadStateStorage>();
     const auto storage_uuid = 
minifi::utils::IdGenerator::getIdGenerator()->generate();
-    state_storage_ = 
std::make_unique<minifi::controllers::VolatileMapStateStorage>(core::controller::ControllerServiceMetadata{
+    state_storage_ = 
std::make_unique<minifi::controllers::VolatileMapStateStorage>(core::ControllerServiceMetadata{
       .uuid = storage_uuid,
       .name = "KeyValueStateStorage",
       .logger = 
logging::LoggerFactory<minifi::controllers::VolatileMapStateStorage>::getLogger(storage_uuid)
diff --git a/extensions/llamacpp/processors/ExtensionInitializer.cpp 
b/extensions/llamacpp/processors/ExtensionInitializer.cpp
index b90b8b133..f55afba69 100644
--- a/extensions/llamacpp/processors/ExtensionInitializer.cpp
+++ b/extensions/llamacpp/processors/ExtensionInitializer.cpp
@@ -34,6 +34,8 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
       .user_data = nullptr,
       .processors_count = 1,
       .processors_ptr = &description,
+      .controller_services_count = 0,
+      .controller_services_ptr = nullptr,
     };
     extension = 
MinifiCreateExtension(minifi::api::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
   });
diff --git a/extensions/opencv/OpenCVLoader.cpp 
b/extensions/opencv/OpenCVLoader.cpp
index 3f91395c4..f159cae8e 100644
--- a/extensions/opencv/OpenCVLoader.cpp
+++ b/extensions/opencv/OpenCVLoader.cpp
@@ -40,7 +40,9 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     .deinit = nullptr,
     .user_data = nullptr,
     .processors_count = 0,
-    .processors_ptr = nullptr
+    .processors_ptr = nullptr,
+    .controller_services_count = 0,
+    .controller_services_ptr = nullptr,
   };
   return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
 }
diff --git a/extensions/python/pythonlibloader/PythonLibLoader.cpp 
b/extensions/python/pythonlibloader/PythonLibLoader.cpp
index cdf0356b7..c2617f186 100644
--- a/extensions/python/pythonlibloader/PythonLibLoader.cpp
+++ b/extensions/python/pythonlibloader/PythonLibLoader.cpp
@@ -112,7 +112,9 @@ extern "C" MinifiExtension* 
MinifiInitExtension(MinifiConfig* config) {
     .deinit = nullptr,
     .user_data = nullptr,
     .processors_count = 0,
-    .processors_ptr = nullptr
+    .processors_ptr = nullptr,
+    .controller_services_count = 0,
+    .controller_services_ptr = nullptr,
   };
   return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
 }
diff --git a/extensions/python/pythonloader/PyProcLoader.cpp 
b/extensions/python/pythonloader/PyProcLoader.cpp
index 55ad4ebef..f37041340 100644
--- a/extensions/python/pythonloader/PyProcLoader.cpp
+++ b/extensions/python/pythonloader/PyProcLoader.cpp
@@ -47,7 +47,9 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
config) {
     .deinit = nullptr,
     .user_data = nullptr,
     .processors_count = 0,
-    .processors_ptr = nullptr
+    .processors_ptr = nullptr,
+    .controller_services_count = 0,
+    .controller_services_ptr = nullptr,
   };
   return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
 }
diff --git a/extensions/sftp/SFTPLoader.cpp b/extensions/sftp/SFTPLoader.cpp
index bb23e9998..8b8d9bffa 100644
--- a/extensions/sftp/SFTPLoader.cpp
+++ b/extensions/sftp/SFTPLoader.cpp
@@ -42,7 +42,9 @@ extern "C" MinifiExtension* MinifiInitExtension(MinifiConfig* 
/*config*/) {
     },
     .user_data = nullptr,
     .processors_count = 0,
-    .processors_ptr = nullptr
+    .processors_ptr = nullptr,
+    .controller_services_count = 0,
+    .controller_services_ptr = nullptr,
   };
   return 
MinifiCreateExtension(minifi::utils::toStringView(MINIFI_API_VERSION), 
&ext_create_info);
 }
diff --git a/libminifi/include/controllers/NetworkPrioritizerService.h 
b/libminifi/include/controllers/NetworkPrioritizerService.h
index 6e8e8593b..a3fc85cb6 100644
--- a/libminifi/include/controllers/NetworkPrioritizerService.h
+++ b/libminifi/include/controllers/NetworkPrioritizerService.h
@@ -51,7 +51,7 @@ class NetworkPrioritizerService : public 
core::controller::ControllerServiceBase
 
  public:
   using ControllerServiceBase::ControllerServiceBase;
-  explicit 
NetworkPrioritizerService(core::controller::ControllerServiceMetadata metadata,
+  explicit NetworkPrioritizerService(core::ControllerServiceMetadata metadata,
                                      std::shared_ptr<utils::timeutils::Clock> 
clock)
       : ControllerServiceBase(std::move(metadata)),
         clock_(std::move(clock)) {
diff --git a/libminifi/include/core/controller/ControllerService.h 
b/libminifi/include/core/controller/ControllerService.h
index c80830db7..0dff3a884 100644
--- a/libminifi/include/core/controller/ControllerService.h
+++ b/libminifi/include/core/controller/ControllerService.h
@@ -27,7 +27,7 @@
 #include "core/ConfigurableComponentImpl.h"
 #include "core/Connectable.h"
 #include "minifi-cpp/core/controller/ControllerServiceApi.h"
-#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
+#include "minifi-cpp/core/ControllerServiceTypeDefinition.h"
 
 namespace org::apache::nifi::minifi::core::controller {
 
@@ -44,6 +44,7 @@ class ControllerService : public ConfigurableComponentImpl, 
public CoreComponent
    public:
     explicit ControllerServiceDescriptorImpl(ControllerService& impl): 
impl_(impl) {}
     void setSupportedProperties(std::span<const PropertyReference> properties) 
override;
+    void setSupportedProperties(std::span<const Property> properties) override;
 
    private:
     ControllerService& impl_;
@@ -130,7 +131,7 @@ class ControllerService : public ConfigurableComponentImpl, 
public CoreComponent
     return false;
   }
 
-  static constexpr auto ImplementsApis = 
std::array<ControllerServiceApiDefinition, 0>{};
+  static constexpr auto ImplementsApis = 
std::array<ControllerServiceTypeDefinition, 0>{};
 
  protected:
   std::unique_ptr<ControllerServiceApi> impl_;
@@ -146,6 +147,10 @@ inline void 
ControllerService::ControllerServiceDescriptorImpl::setSupportedProp
   impl_.setSupportedProperties(properties);
 }
 
+inline void 
ControllerService::ControllerServiceDescriptorImpl::setSupportedProperties(std::span<const
 Property> properties) {
+  impl_.setSupportedProperties(properties);
+}
+
 inline nonstd::expected<std::string, std::error_code> 
ControllerService::ControllerServiceContextImpl::getProperty(std::string_view 
name) const {
   return impl_.getProperty(name);
 }
diff --git a/libminifi/include/utils/CControllerService.h 
b/libminifi/include/utils/CControllerService.h
new file mode 100644
index 000000000..0d0ea4929
--- /dev/null
+++ b/libminifi/include/utils/CControllerService.h
@@ -0,0 +1,110 @@
+/**
+* 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
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "minifi-c/minifi-c.h"
+#include "minifi-cpp/Exception.h"
+#include "minifi-cpp/core/ControllerServiceMetadata.h"
+#include "minifi-cpp/core/Property.h"
+#include "minifi-cpp/core/controller/ControllerServiceApi.h"
+
+namespace org::apache::nifi::minifi::utils {
+class CControllerService;
+
+
+struct CControllerServiceClassDescription {
+  std::string group_name;
+  std::string name;
+  std::string version;
+
+  std::vector<core::Property> class_properties;
+
+  MinifiControllerServiceCallbacks callbacks;
+};
+
+class CControllerService final : public 
core::controller::ControllerServiceApi, public 
core::controller::ControllerServiceInterface {
+ public:
+  CControllerService(CControllerServiceClassDescription class_description, 
core::ControllerServiceMetadata metadata)
+    : class_description_(std::move(class_description)),
+      metadata_(std::move(metadata)) {
+    MinifiControllerServiceMetadata c_metadata;
+    auto uuid_str = metadata_.uuid.to_string();
+    c_metadata.uuid = MinifiStringView{.data = uuid_str.data(), .length = 
uuid_str.length()};
+    c_metadata.name = MinifiStringView{.data = metadata_.name.data(), .length 
= metadata_.name.length()};
+    c_metadata.logger = reinterpret_cast<MinifiLogger*>(&metadata_.logger);
+    impl_ = class_description_.callbacks.create(c_metadata);
+  }
+  CControllerService(CControllerServiceClassDescription class_description, 
core::ControllerServiceMetadata metadata, gsl::owner<void*> impl)
+      : class_description_(std::move(class_description)),
+        impl_(impl),
+        metadata_(std::move(metadata)) {}
+  ~CControllerService() override {
+    class_description_.callbacks.destroy(impl_);
+  }
+
+  void initialize(core::controller::ControllerServiceDescriptor& descriptor) 
override {
+    
descriptor.setSupportedProperties(std::span(class_description_.class_properties));
+  }
+
+  void onEnable(core::controller::ControllerServiceContext& 
controller_service_context,
+      const std::shared_ptr<Configure>&,
+      const 
std::vector<std::shared_ptr<core::controller::ControllerServiceInterface>>&) 
override {
+    const auto enable_status = class_description_.callbacks.enable(impl_, 
reinterpret_cast<MinifiControllerServiceContext*>(&controller_service_context));
+    if (enable_status != MINIFI_STATUS_SUCCESS) {
+      throw Exception(PROCESS_SCHEDULE_EXCEPTION, "Could not enable controller 
service");
+    }
+  }
+
+  void notifyStop() override {
+    class_description_.callbacks.notifyStop(impl_);
+  }
+
+  ControllerServiceInterface* getControllerServiceInterface() override {
+    return this;
+  }
+
+  [[nodiscard]] std::string getName() const {
+    return metadata_.name;
+  }
+
+  [[nodiscard]] Identifier getUUID() const {
+    return metadata_.uuid;
+  }
+
+  [[nodiscard]] void* getImpl() const {
+    return this->impl_;
+  }
+
+  [[nodiscard]] const CControllerServiceClassDescription& 
getClassDescription() const {
+    return class_description_;
+  }
+
+ private:
+  CControllerServiceClassDescription class_description_;
+  gsl::owner<void*> impl_;
+  minifi::core::ControllerServiceMetadata metadata_;
+};
+
+void useCControllerServiceClassDescription(const 
MinifiControllerServiceClassDefinition& class_description,
+    const BundleIdentifier& bundle_id,
+    const std::function<void(ClassDescription, 
CControllerServiceClassDescription)>& fn);
+
+}  // namespace org::apache::nifi::minifi::utils
diff --git a/libminifi/include/utils/CProcessor.h 
b/libminifi/include/utils/CProcessor.h
index bef73d9e9..6b8e6660e 100644
--- a/libminifi/include/utils/CProcessor.h
+++ b/libminifi/include/utils/CProcessor.h
@@ -18,6 +18,7 @@
 #pragma once
 
 #include <string>
+#include <utility>
 
 #include "minifi-cpp/core/Annotation.h"
 #include "core/ProcessorMetrics.h"
@@ -63,18 +64,18 @@ class CProcessor : public minifi::core::ProcessorApi {
   CProcessor(CProcessorClassDescription class_description, 
minifi::core::ProcessorMetadata metadata)
       : class_description_(std::move(class_description)),
         metrics_extension_(std::make_shared<CProcessorMetricsWrapper>(*this)) {
-    metadata_ = metadata;
+    metadata_ = std::move(metadata);
     MinifiProcessorMetadata c_metadata;
-    auto uuid_str = metadata.uuid.to_string();
+    const auto uuid_str = metadata.uuid.to_string();
     c_metadata.uuid = MinifiStringView{.data = uuid_str.data(), .length = 
uuid_str.length()};
-    c_metadata.name = MinifiStringView{.data = metadata.name.data(), .length = 
metadata.name.length()};
+    c_metadata.name = MinifiStringView{.data = metadata_.name.data(), .length 
= metadata_.name.length()};
     c_metadata.logger = reinterpret_cast<MinifiLogger*>(&metadata_.logger);
     impl_ = class_description_.callbacks.create(c_metadata);
   }
   CProcessor(CProcessorClassDescription class_description, 
minifi::core::ProcessorMetadata metadata, gsl::owner<void*> impl)
       : class_description_(std::move(class_description)),
         impl_(impl),
-        metadata_(metadata),
+        metadata_(std::move(metadata)),
         metrics_extension_(std::make_shared<CProcessorMetricsWrapper>(*this)) 
{}
   ~CProcessor() override {
     class_description_.callbacks.destroy(impl_);
diff --git a/libminifi/src/controllers/SSLContextService.cpp 
b/libminifi/src/controllers/SSLContextService.cpp
index 584b5109d..5d7cfc72e 100644
--- a/libminifi/src/controllers/SSLContextService.cpp
+++ b/libminifi/src/controllers/SSLContextService.cpp
@@ -598,7 +598,7 @@ void SSLContextService::verifyCertificateExpiration() {
 std::shared_ptr<SSLContextService> 
SSLContextService::createAndEnable(std::string_view name, const 
std::shared_ptr<Configure>& configuration) {
   auto uuid = utils::IdGenerator::getIdGenerator()->generate();
   auto logger = 
core::logging::LoggerFactory<SSLContextService>::getLogger(uuid);
-  auto service = std::make_shared<core::controller::ControllerService>(name, 
uuid, 
std::make_unique<SSLContextService>(core::controller::ControllerServiceMetadata{
+  auto service = std::make_shared<core::controller::ControllerService>(name, 
uuid, std::make_unique<SSLContextService>(core::ControllerServiceMetadata{
     .uuid = uuid,
     .name = std::string{name},
     .logger = logger,
diff --git a/libminifi/src/minifi-c.cpp b/libminifi/src/minifi-c.cpp
index 6a2d947ab..9c85a26bb 100644
--- a/libminifi/src/minifi-c.cpp
+++ b/libminifi/src/minifi-c.cpp
@@ -37,11 +37,16 @@
 #include "core/extension/ExtensionManager.h"
 #include "utils/PropertyErrors.h"
 #include "utils/CProcessor.h"
+#include "utils/CControllerService.h"
 
 namespace minifi = org::apache::nifi::minifi;
 
 namespace {
 
+MinifiStringView minifiStringView(const std::string_view s) {
+  return MinifiStringView{.data = s.data(), .length = s.size()};
+}
+
 std::string toString(MinifiStringView sv) {
   return {sv.data, sv.length};
 }
@@ -146,6 +151,37 @@ class CProcessorFactory : public 
minifi::core::ProcessorFactory {
   minifi::utils::CProcessorClassDescription class_description_;
 };
 
+class CControllerServiceFactory : public 
minifi::core::controller::ControllerServiceFactory {
+ public:
+  CControllerServiceFactory(std::string group_name, std::string class_name, 
minifi::utils::CControllerServiceClassDescription class_description)
+    : group_name_(std::move(group_name)),
+      class_name_(std::move(class_name)),
+      class_description_(std::move(class_description)) {}
+  std::unique_ptr<minifi::core::controller::ControllerServiceApi> 
create(minifi::core::ControllerServiceMetadata metadata) override {
+    return 
std::make_unique<minifi::utils::CControllerService>(class_description_, 
std::move(metadata));
+  }
+
+  [[nodiscard]] std::string getGroupName() const override {
+    return group_name_;
+  }
+
+  [[nodiscard]] std::string getClassName() const override {
+    return class_name_;
+  }
+
+  CControllerServiceFactory() = delete;
+  CControllerServiceFactory(const CControllerServiceFactory&) = delete;
+  CControllerServiceFactory& operator=(const CControllerServiceFactory&) = 
delete;
+  CControllerServiceFactory(CControllerServiceFactory&&) = delete;
+  CControllerServiceFactory& operator=(CControllerServiceFactory&&) = delete;
+  ~CControllerServiceFactory() override = default;
+
+ private:
+  std::string group_name_;
+  std::string class_name_;
+  minifi::utils::CControllerServiceClassDescription class_description_;
+};
+
 MinifiExtension* MinifiCreateExtensionImpl(MinifiStringView /*api_version*/, 
const MinifiExtensionCreateInfo* extension_create_info) {
   gsl_Assert(extension_create_info);
   auto extension_name = toString(extension_create_info->name);
@@ -162,6 +198,14 @@ MinifiExtension* 
MinifiCreateExtensionImpl(MinifiStringView /*api_version*/, con
       bundle_components.processors.emplace_back(description);
     });
   }
+  for (size_t controller_service_idx = 0; controller_service_idx < 
extension_create_info->controller_services_count; ++controller_service_idx) {
+    
minifi::utils::useCControllerServiceClassDescription(extension_create_info->controller_services_ptr[controller_service_idx],
 bundle, [&](const auto& description, const auto& c_class_description) {
+      
minifi::core::ClassLoader::getDefaultClassLoader().getClassLoader(extension_name).registerClass(
+        c_class_description.name,
+        std::make_unique<CControllerServiceFactory>(extension_name, 
toString(extension_create_info->controller_services_ptr[controller_service_idx].full_name),
 c_class_description));
+      bundle_components.controller_services.emplace_back(description);
+    });
+  }
   return reinterpret_cast<MinifiExtension*>(new 
org::apache::nifi::minifi::core::extension::Extension::Info{
     .name = toString(extension_create_info->name),
     .version = toString(extension_create_info->version),
@@ -245,6 +289,35 @@ void useCProcessorClassDescription(const 
MinifiProcessorClassDefinition& class_d
   fn(description, c_class_description);
 }
 
+void useCControllerServiceClassDescription(const 
MinifiControllerServiceClassDefinition& class_description,
+    const BundleIdentifier& bundle_id,
+    const std::function<void(ClassDescription, 
CControllerServiceClassDescription)>& fn) {
+  std::vector<minifi::core::Property> properties;
+  properties.reserve(class_description.class_properties_count);
+  for (size_t i = 0; i < class_description.class_properties_count; ++i) {
+    
properties.push_back(createProperty(&class_description.class_properties_ptr[i]));
+  }
+
+  auto name_segments = 
minifi::utils::string::split(toStringView(class_description.full_name), "::");
+  gsl_Assert(!name_segments.empty());
+
+  minifi::ClassDescription description{
+    .type_ = minifi::ResourceType::ControllerService,
+    .short_name_ = name_segments.back(),
+    .full_name_ = minifi::utils::string::join(".", name_segments),
+    .description_ = toString(class_description.description),
+    .class_properties_ = properties,
+  };
+
+  minifi::utils::CControllerServiceClassDescription c_class_description{
+    .group_name = bundle_id.name,
+    .name = name_segments.back(),
+    .version = bundle_id.version,
+    .class_properties = properties,
+    .callbacks = class_description.callbacks
+  };
+  fn(description, c_class_description);
+}
 }  // namespace org::apache::nifi::minifi::utils
 
 extern "C" {
@@ -266,7 +339,7 @@ MinifiStatus 
MinifiProcessContextGetProperty(MinifiProcessContext* context, Mini
   auto result = 
reinterpret_cast<minifi::core::ProcessContext*>(context)->getProperty(toStringView(property_name),
       flowfile != MINIFI_NULL ? 
reinterpret_cast<std::shared_ptr<minifi::core::FlowFile>*>(flowfile)->get() : 
nullptr);
   if (result) {
-    result_cb(user_ctx, MinifiStringView{.data = result.value().data(), 
.length = result.value().length()});
+    result_cb(user_ctx, minifiStringView(result.value()));
     return MINIFI_STATUS_SUCCESS;
   }
   switch 
(static_cast<minifi::core::PropertyErrorCode>(result.error().value())) {
@@ -281,7 +354,7 @@ MinifiStatus 
MinifiProcessContextGetProperty(MinifiProcessContext* context, Mini
 void MinifiProcessContextGetProcessorName(MinifiProcessContext* context, 
void(*cb)(void* user_ctx, MinifiStringView result), void* user_ctx) {
   gsl_Assert(context != MINIFI_NULL);
   auto name = 
reinterpret_cast<minifi::core::ProcessContext*>(context)->getProcessorInfo().getName();
-  cb(user_ctx, MinifiStringView{.data = name.data(), .length = name.length()});
+  cb(user_ctx, minifiStringView(name));
 }
 
 MinifiBool MinifiProcessContextHasNonEmptyProperty(MinifiProcessContext* 
context, MinifiStringView property_name) {
@@ -293,10 +366,7 @@ void MinifiConfigGet(MinifiConfig* configure, 
MinifiStringView key, void(*cb)(vo
   gsl_Assert(configure != MINIFI_NULL);
   auto value = 
reinterpret_cast<minifi::Configure*>(configure)->get(toString(key));
   if (value) {
-    cb(user_ctx, MinifiStringView{
-      .data = value->data(),
-      .length = value->length()
-    });
+    cb(user_ctx, minifiStringView(*value));
   }
 }
 
@@ -420,7 +490,7 @@ void MinifiStatusToString(MinifiStatus status, 
void(*cb)(void* user_ctx, MinifiS
       default: return "Unknown error";
     }
   }();
-  cb(user_ctx, MinifiStringView{.data = message.data(), .length = 
message.size()});
+  cb(user_ctx, minifiStringView(message));
 }
 
 void MinifiFlowFileSetAttribute(MinifiProcessSession* session, MinifiFlowFile* 
flowfile, MinifiStringView attribute_name, const MinifiStringView* 
attribute_value) {
@@ -442,7 +512,7 @@ MinifiBool MinifiFlowFileGetAttribute(MinifiProcessSession* 
session, MinifiFlowF
   if (!value.has_value()) {
     return false;
   }
-  cb(user_ctx, MinifiStringView{.data = value->data(), .length = 
value->size()});
+  cb(user_ctx, minifiStringView(*value));
   return true;
 }
 
@@ -451,8 +521,58 @@ void MinifiFlowFileGetAttributes(MinifiProcessSession* 
session, MinifiFlowFile*
   gsl_Assert(session != MINIFI_NULL);
   gsl_Assert(flowfile != MINIFI_NULL);
   for (auto& [key, value] : 
(*reinterpret_cast<std::shared_ptr<minifi::core::FlowFile>*>(flowfile))->getAttributes())
 {
-    cb(user_ctx, MinifiStringView{.data = key.data(), .length = key.size()}, 
MinifiStringView{.data = value.data(), .length = value.size()});
+    cb(user_ctx, minifiStringView(key), minifiStringView(value));
   }
 }
 
+MinifiStatus 
MinifiControllerServiceContextGetProperty(MinifiControllerServiceContext* 
context, MinifiStringView property_name,
+    void (*result_cb)(void* user_ctx, MinifiStringView result), void* 
user_ctx) {
+  gsl_Assert(context != MINIFI_NULL);
+  auto result = 
reinterpret_cast<minifi::core::controller::ControllerServiceContext*>(context)->getProperty(toStringView(property_name));
+  if (result) {
+    result_cb(user_ctx, minifiStringView(result.value()));
+    return MINIFI_STATUS_SUCCESS;
+  }
+  switch 
(static_cast<minifi::core::PropertyErrorCode>(result.error().value())) {
+    case minifi::core::PropertyErrorCode::NotSupportedProperty: return 
MINIFI_STATUS_NOT_SUPPORTED_PROPERTY;
+    case minifi::core::PropertyErrorCode::DynamicPropertiesNotSupported: 
return MINIFI_STATUS_DYNAMIC_PROPERTIES_NOT_SUPPORTED;
+    case minifi::core::PropertyErrorCode::PropertyNotSet: return 
MINIFI_STATUS_PROPERTY_NOT_SET;
+    case minifi::core::PropertyErrorCode::ValidationFailed: return 
MINIFI_STATUS_VALIDATION_FAILED;
+    default: return MINIFI_STATUS_UNKNOWN_ERROR;
+  }
+}
+
+
+MinifiStatus MinifiProcessContextGetControllerService(
+    MinifiProcessContext* process_context,
+    MinifiStringView controller_service_name,
+    void(*cb)(
+        void* user_ctx,
+        void* service,
+        MinifiStringView type,
+        MinifiStringView group,
+        MinifiStringView version),
+    void* user_ctx) {
+
+  gsl_Assert(process_context != MINIFI_NULL);
+  const auto context = 
reinterpret_cast<minifi::core::ProcessContext*>(process_context);
+  const auto name_str = std::string{toStringView(controller_service_name)};
+  const auto service_shared_ptr = context->getControllerService(name_str, 
context->getProcessorInfo().getUUID());
+  if (!service_shared_ptr) {
+    return MINIFI_STATUS_UNKNOWN_ERROR;
+  }
+  const minifi::utils::CControllerService* c_controller_service = 
dynamic_cast<minifi::utils::CControllerService*>(&*service_shared_ptr);
+  if (c_controller_service) {
+    const auto class_description = c_controller_service->getClassDescription();
+    cb(user_ctx,
+      c_controller_service->getImpl(),
+      minifiStringView(class_description.group_name),
+      minifiStringView(class_description.name),
+      minifiStringView(class_description.version));
+    return MINIFI_STATUS_SUCCESS;
+  }
+  return MINIFI_STATUS_UNKNOWN_ERROR;  // TODO(mzink) better error handling
+}
+
+
 }  // extern "C"
diff --git a/libminifi/src/properties/Properties.cpp 
b/libminifi/src/properties/Properties.cpp
index 1624a8557..2f5723a64 100644
--- a/libminifi/src/properties/Properties.cpp
+++ b/libminifi/src/properties/Properties.cpp
@@ -22,6 +22,7 @@
 #include <string>
 
 #include "core/logging/LoggerConfiguration.h"
+#include "minifi-cpp/core/PropertyValidator.h"
 #include "properties/Configuration.h"
 #include "properties/PropertiesFile.h"
 #include "utils/StringUtils.h"
diff --git a/libminifi/test/libtest/integration/HTTPHandlers.h 
b/libminifi/test/libtest/integration/HTTPHandlers.h
index 25a0dba5d..40304948a 100644
--- a/libminifi/test/libtest/integration/HTTPHandlers.h
+++ b/libminifi/test/libtest/integration/HTTPHandlers.h
@@ -21,21 +21,22 @@
 #include <map>
 #include <memory>
 #include <optional>
+#include <set>
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
-#include <set>
-#include <unordered_map>
 
-#include "civetweb.h"
 #include "CivetServer.h"
-#include "concurrentqueue.h"
-#include "rapidjson/document.h"
-#include "utils/HTTPUtils.h"
 #include "ServerAwareHandler.h"
 #include "c2/C2Payload.h"
+#include "civetweb.h"
+#include "concurrentqueue.h"
+#include "minifi-cpp/properties/Configure.h"
 #include "properties/Configure.h"
+#include "rapidjson/document.h"
 #include "unit/Catch.h"
+#include "utils/HTTPUtils.h"
 
 namespace org::apache::nifi::minifi::test {
 
diff --git a/libminifi/test/libtest/unit/ControllerServiceUtils.h 
b/libminifi/test/libtest/unit/ControllerServiceUtils.h
index ff19982d3..ee8d79c37 100644
--- a/libminifi/test/libtest/unit/ControllerServiceUtils.h
+++ b/libminifi/test/libtest/unit/ControllerServiceUtils.h
@@ -29,7 +29,7 @@ std::unique_ptr<core::controller::ControllerService> 
make_controller_service(std
   if (!uuid) {
     uuid = minifi::utils::IdGenerator::getIdGenerator()->generate();
   }
-  auto processor_impl = 
std::make_unique<T>(core::controller::ControllerServiceMetadata{
+  auto processor_impl = std::make_unique<T>(core::ControllerServiceMetadata{
       .uuid = uuid.value(),
       .name = std::string{name},
       .logger = 
minifi::core::logging::LoggerFactory<T>::getLogger(uuid.value())
diff --git a/libminifi/test/unit/NetworkPrioritizerServiceTests.cpp 
b/libminifi/test/unit/NetworkPrioritizerServiceTests.cpp
index a54ba109a..a05d21ad2 100644
--- a/libminifi/test/unit/NetworkPrioritizerServiceTests.cpp
+++ b/libminifi/test/unit/NetworkPrioritizerServiceTests.cpp
@@ -31,7 +31,7 @@ std::shared_ptr<core::controller::ControllerService> 
createNetworkPrioritizerSer
     const std::shared_ptr<utils::timeutils::Clock>& clock = 
std::make_shared<minifi::test::utils::ManualClock>()) {
   return std::make_shared<core::controller::ControllerService>(
     name, utils::Identifier{},
-    
std::make_unique<minifi::controllers::NetworkPrioritizerService>(core::controller::ControllerServiceMetadata{
+    
std::make_unique<minifi::controllers::NetworkPrioritizerService>(core::ControllerServiceMetadata{
       .uuid = utils::Identifier{},
       .name = name,
       .logger = 
logging::LoggerFactory<minifi::controllers::NetworkPrioritizerService>::getLogger()
diff --git 
a/minifi-api/include/minifi-cpp/core/controller/ControllerServiceMetadata.h 
b/minifi-api/common/include/minifi-cpp/core/ControllerServiceMetadata.h
similarity index 84%
rename from 
minifi-api/include/minifi-cpp/core/controller/ControllerServiceMetadata.h
rename to minifi-api/common/include/minifi-cpp/core/ControllerServiceMetadata.h
index 3c6fb63b7..22200a84d 100644
--- a/minifi-api/include/minifi-cpp/core/controller/ControllerServiceMetadata.h
+++ b/minifi-api/common/include/minifi-cpp/core/ControllerServiceMetadata.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
@@ -21,7 +21,7 @@
 #include "minifi-cpp/utils/Id.h"
 #include "minifi-cpp/core/logging/Logger.h"
 
-namespace org::apache::nifi::minifi::core::controller {
+namespace org::apache::nifi::minifi::core {
 
 struct ControllerServiceMetadata {
   utils::Identifier uuid;
@@ -29,4 +29,4 @@ struct ControllerServiceMetadata {
   std::shared_ptr<logging::Logger> logger;
 };
 
-}  // namespace org::apache::nifi::minifi::core::controller
+}  // namespace org::apache::nifi::minifi::core
diff --git a/minifi-api/include/minifi-c/minifi-c.h 
b/minifi-api/include/minifi-c/minifi-c.h
index 97af61f5b..811bd73ec 100644
--- a/minifi-api/include/minifi-c/minifi-c.h
+++ b/minifi-api/include/minifi-c/minifi-c.h
@@ -96,6 +96,8 @@ typedef struct MinifiExtension MinifiExtension;
 typedef struct MinifiPublishedMetrics MinifiPublishedMetrics;
 typedef struct MinifiApiVersion MinifiApiVersion;
 
+typedef struct MinifiControllerServiceContext MinifiControllerServiceContext;
+
 typedef enum MinifiStatus {
   MINIFI_STATUS_SUCCESS = 0,
   MINIFI_STATUS_UNKNOWN_ERROR = 1,
@@ -149,6 +151,12 @@ typedef struct MinifiProcessorMetadata {
   MinifiLogger* logger;  // borrowed reference, live until the processor is 
live
 } MinifiProcessorMetadata;
 
+typedef struct MinifiControllerServiceMetadata {
+  MinifiStringView uuid;
+  MinifiStringView name;
+  MinifiLogger* logger;  // borrowed reference, live until the controller 
service is live
+} MinifiControllerServiceMetadata;
+
 typedef struct MinifiProcessorCallbacks {
   MINIFI_OWNED void*(*create)(MinifiProcessorMetadata);
   void(*destroy)(MINIFI_OWNED void*);
@@ -161,6 +169,13 @@ typedef struct MinifiProcessorCallbacks {
   MINIFI_OWNED MinifiPublishedMetrics*(*calculateMetrics)(void*);
 } MinifiProcessorCallbacks;
 
+typedef struct MinifiControllerServiceCallbacks {
+  MINIFI_OWNED void*(*create)(MinifiControllerServiceMetadata);
+  void(*destroy)(MINIFI_OWNED void*);
+  MinifiStatus(*enable)(void*, MinifiControllerServiceContext*);
+  void(*notifyStop)(void*);
+} MinifiControllerServiceCallbacks;
+
 typedef struct MinifiProcessorClassDefinition {
   MinifiStringView full_name;  // '::'-delimited fully qualified name e.g. 
'org::apache::nifi::minifi::GenerateFlowFile'
   MinifiStringView description;
@@ -180,6 +195,16 @@ typedef struct MinifiProcessorClassDefinition {
   MinifiProcessorCallbacks callbacks;
 } MinifiProcessorClassDefinition;
 
+typedef struct MinifiControllerServiceClassDefinition {
+  MinifiStringView full_name;  // '::'-delimited fully qualified name e.g. 
'org::apache::nifi::minifi::extensions::gcp::GCPCredentialsControllerService
+  MinifiStringView description;
+  size_t class_properties_count;
+  const MinifiPropertyDefinition* class_properties_ptr;
+
+  MinifiControllerServiceCallbacks callbacks;
+} MinifiControllerServiceClassDefinition;
+
+
 typedef struct MinifiExtensionCreateInfo {
   MinifiStringView name;
   MinifiStringView version;
@@ -187,6 +212,8 @@ typedef struct MinifiExtensionCreateInfo {
   void* user_data;
   size_t processors_count;
   const MinifiProcessorClassDefinition* processors_ptr;
+  size_t controller_services_count;
+  const MinifiControllerServiceClassDefinition* controller_services_ptr;
 } MinifiExtensionCreateInfo;
 
 // api_version is used to provide backwards compatible changes to the 
MinifiExtensionCreateInfo structure,
@@ -201,6 +228,9 @@ MinifiStatus 
MinifiProcessContextGetProperty(MinifiProcessContext* context, Mini
 void MinifiProcessContextGetProcessorName(MinifiProcessContext* context, 
void(*cb)(void* user_ctx, MinifiStringView processor_name), void* user_ctx);
 MinifiBool MinifiProcessContextHasNonEmptyProperty(MinifiProcessContext* 
context, MinifiStringView property_name);
 
+MinifiStatus MinifiProcessContextGetControllerService(MinifiProcessContext*, 
MinifiStringView controller_service_name,
+    void(*cb)(void* user_ctx, void* service, MinifiStringView type, 
MinifiStringView group, MinifiStringView version), void* user_ctx);
+
 void MinifiLoggerSetMaxLogSize(MinifiLogger*, int32_t);
 void MinifiLoggerLogString(MinifiLogger*, MinifiLogLevel, MinifiStringView);
 MinifiBool MinifiLoggerShouldLog(MinifiLogger*, MinifiLogLevel);
@@ -229,6 +259,11 @@ MinifiBool 
MinifiFlowFileGetAttribute(MinifiProcessSession* session, MinifiFlowF
                                       void(*cb)(void* user_ctx, 
MinifiStringView attribute_value), void* user_ctx);
 void MinifiFlowFileGetAttributes(MinifiProcessSession* session, 
MinifiFlowFile* flowfile, void(*cb)(void* user_ctx, MinifiStringView 
attribute_name, MinifiStringView attribute_value), void* user_ctx);
 
+MinifiStatus 
MinifiControllerServiceContextGetProperty(MinifiControllerServiceContext* 
context,
+    MinifiStringView property_name,
+    void(*cb)(void* user_ctx, MinifiStringView property_value),
+    void* user_ctx);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif  // __cplusplus
diff --git a/minifi-api/include/minifi-cpp/agent/agent_docs.h 
b/minifi-api/include/minifi-cpp/agent/agent_docs.h
index 912377d39..b6a6b9017 100644
--- a/minifi-api/include/minifi-cpp/agent/agent_docs.h
+++ b/minifi-api/include/minifi-cpp/agent/agent_docs.h
@@ -22,7 +22,7 @@
 #include <vector>
 
 #include "minifi-cpp/core/Annotation.h"
-#include "minifi-cpp/core/ControllerServiceApi.h"
+#include "minifi-cpp/core/ControllerServiceType.h"
 #include "minifi-cpp/core/DynamicProperty.h"
 #include "minifi-cpp/core/OutputAttribute.h"
 #include "minifi-cpp/core/Property.h"
@@ -44,7 +44,7 @@ struct ClassDescription {
   std::vector<core::DynamicProperty> dynamic_properties_{};
   std::vector<core::Relationship> class_relationships_{};
   std::vector<core::OutputAttribute> output_attributes_{};
-  std::vector<core::ControllerServiceApi> api_implementations{};
+  std::vector<core::ControllerServiceType> 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 f91dee361..2b8b8731d 100644
--- a/minifi-api/include/minifi-cpp/controllers/RecordSetReader.h
+++ b/minifi-api/include/minifi-cpp/controllers/RecordSetReader.h
@@ -17,7 +17,7 @@
 #pragma once
 
 #include "minifi-cpp/core/controller/ControllerServiceInterface.h"
-#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
+#include "minifi-cpp/core/ControllerServiceTypeDefinition.h"
 #include "minifi-cpp/core/Record.h"
 #include "utils/Enum.h"
 #include "utils/ProcessorConfigUtils.h"
@@ -28,7 +28,7 @@ namespace org::apache::nifi::minifi::core {
 
 class RecordSetReader : public controller::ControllerServiceInterface {
  public:
-  static constexpr auto ProvidesApi = core::ControllerServiceApiDefinition{
+  static constexpr auto ProvidesApi = core::ControllerServiceTypeDefinition{
     .artifact = "minifi-system",
     .group = "org.apache.nifi.minifi",
     .type = "org.apache.nifi.minifi.core.RecordSetReader",
diff --git a/minifi-api/include/minifi-cpp/controllers/RecordSetWriter.h 
b/minifi-api/include/minifi-cpp/controllers/RecordSetWriter.h
index bbe1ebdde..8453f2215 100644
--- a/minifi-api/include/minifi-cpp/controllers/RecordSetWriter.h
+++ b/minifi-api/include/minifi-cpp/controllers/RecordSetWriter.h
@@ -18,7 +18,7 @@
 
 #include "minifi-cpp/core/controller/ControllerServiceInterface.h"
 
-#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
+#include "minifi-cpp/core/ControllerServiceTypeDefinition.h"
 #include "minifi-cpp/core/FlowFile.h"
 #include "minifi-cpp/core/ProcessSession.h"
 #include "minifi-cpp/core/Record.h"
@@ -28,7 +28,7 @@ namespace org::apache::nifi::minifi::core {
 
 class RecordSetWriter : public controller::ControllerServiceInterface {
  public:
-  static constexpr auto ProvidesApi = core::ControllerServiceApiDefinition{
+  static constexpr auto ProvidesApi = core::ControllerServiceTypeDefinition{
     .artifact = "minifi-system",
     .group = "org.apache.nifi.minifi",
     .type = "org.apache.nifi.minifi.core.RecordSetWriter",
diff --git 
a/minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h 
b/minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h
index 68d79380b..3058ade0b 100644
--- a/minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h
+++ b/minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h
@@ -16,12 +16,12 @@
  */
 #pragma once
 
-#include <iostream>
+#include <filesystem>
 #include <memory>
 #include <string>
 #include <utility>
 
-#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
+#include "minifi-cpp/core/ControllerServiceTypeDefinition.h"
 #include "minifi-cpp/agent/agent_version.h"
 #include "minifi-cpp/core/controller/ControllerServiceInterface.h"
 
@@ -37,7 +37,7 @@ namespace org::apache::nifi::minifi::controllers {
  */
 class SSLContextServiceInterface : public 
core::controller::ControllerServiceInterface {
  public:
-  static constexpr auto ProvidesApi = core::ControllerServiceApiDefinition{
+  static constexpr auto ProvidesApi = core::ControllerServiceTypeDefinition{
     .artifact = "minifi-system",
     .group = "org.apache.nifi.minifi",
     .type = "org.apache.nifi.minifi.controllers.SSLContextServiceInterface",
diff --git a/minifi-api/include/minifi-cpp/core/ControllerServiceApi.h 
b/minifi-api/include/minifi-cpp/core/ControllerServiceType.h
similarity index 84%
rename from minifi-api/include/minifi-cpp/core/ControllerServiceApi.h
rename to minifi-api/include/minifi-cpp/core/ControllerServiceType.h
index fe0d450f7..6d5b39de3 100644
--- a/minifi-api/include/minifi-cpp/core/ControllerServiceApi.h
+++ b/minifi-api/include/minifi-cpp/core/ControllerServiceType.h
@@ -17,16 +17,16 @@
 #pragma once
 
 #include <string>
-#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
+#include "minifi-cpp/core/ControllerServiceTypeDefinition.h"
 
 namespace org::apache::nifi::minifi::core {
 
-struct ControllerServiceApi {
+struct ControllerServiceType {
   std::string artifact;
   std::string group;
   std::string type;
 
-  ControllerServiceApi(const ControllerServiceApiDefinition& definition)  // 
NOLINT(runtime/explicit)
+  ControllerServiceType(const ControllerServiceTypeDefinition& definition)  // 
NOLINT(runtime/explicit)
     : artifact(definition.artifact),
       group(definition.group),
       type(definition.type) {}
diff --git 
a/minifi-api/include/minifi-cpp/core/ControllerServiceApiDefinition.h 
b/minifi-api/include/minifi-cpp/core/ControllerServiceTypeDefinition.h
similarity index 96%
rename from minifi-api/include/minifi-cpp/core/ControllerServiceApiDefinition.h
rename to minifi-api/include/minifi-cpp/core/ControllerServiceTypeDefinition.h
index 37084baea..f40d871a6 100644
--- a/minifi-api/include/minifi-cpp/core/ControllerServiceApiDefinition.h
+++ b/minifi-api/include/minifi-cpp/core/ControllerServiceTypeDefinition.h
@@ -20,7 +20,7 @@
 
 namespace org::apache::nifi::minifi::core {
 
-struct ControllerServiceApiDefinition {
+struct ControllerServiceTypeDefinition {
   std::string_view artifact;
   std::string_view group;
   std::string_view type;
diff --git 
a/minifi-api/include/minifi-cpp/core/controller/ControllerServiceDescriptor.h 
b/minifi-api/include/minifi-cpp/core/controller/ControllerServiceDescriptor.h
index 525a6d6ce..39fb6da89 100644
--- 
a/minifi-api/include/minifi-cpp/core/controller/ControllerServiceDescriptor.h
+++ 
b/minifi-api/include/minifi-cpp/core/controller/ControllerServiceDescriptor.h
@@ -26,6 +26,7 @@ class ControllerServiceDescriptor {
   virtual ~ControllerServiceDescriptor() = default;
 
   virtual void setSupportedProperties(std::span<const PropertyReference> 
properties) = 0;
+  virtual void setSupportedProperties(std::span<const Property> properties) = 
0;
 };
 
 }  // namespace org::apache::nifi::minifi::core::controller
diff --git 
a/minifi-api/include/minifi-cpp/core/controller/ControllerServiceFactory.h 
b/minifi-api/include/minifi-cpp/core/controller/ControllerServiceFactory.h
index 725944bfa..aafc571dc 100644
--- a/minifi-api/include/minifi-cpp/core/controller/ControllerServiceFactory.h
+++ b/minifi-api/include/minifi-cpp/core/controller/ControllerServiceFactory.h
@@ -17,10 +17,11 @@
 
 #pragma once
 
-#include <string>
 #include <memory>
+#include <string>
 #include <utility>
-#include "minifi-cpp/core/controller/ControllerServiceMetadata.h"
+
+#include "minifi-cpp/core/ControllerServiceMetadata.h"
 
 namespace org::apache::nifi::minifi::core::controller {
 
diff --git 
a/minifi-api/include/minifi-cpp/core/controller/ControllerServiceInterface.h 
b/minifi-api/include/minifi-cpp/core/controller/ControllerServiceInterface.h
index e1d7da19e..799446f69 100644
--- a/minifi-api/include/minifi-cpp/core/controller/ControllerServiceInterface.h
+++ b/minifi-api/include/minifi-cpp/core/controller/ControllerServiceInterface.h
@@ -17,23 +17,8 @@
  */
 #pragma once
 
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "minifi-cpp/properties/Configure.h"
-#include "minifi-cpp/core/ConfigurableComponent.h"
-#include "minifi-cpp/core/Connectable.h"
-
 namespace org::apache::nifi::minifi::core::controller {
 
-/**
- * Controller Service base class that contains some pure virtual methods.
- *
- * Design: OnEnable is executed when the controller service is being enabled.
- * Note that keeping state here must be protected  in this function.
- */
 class ControllerServiceInterface {
  public:
   virtual ~ControllerServiceInterface() = default;
diff --git a/minifi-api/minifi-c-api.def b/minifi-api/minifi-c-api.def
index d7faf9426..de4b384b0 100644
--- a/minifi-api/minifi-c-api.def
+++ b/minifi-api/minifi-c-api.def
@@ -2,9 +2,11 @@ LIBRARY core-minifi.dll
 EXPORTS
   MinifiCreateExtension_0_1
   MinifiPublishedMetricsCreate
+  MinifiProcessContextGetControllerService
   MinifiProcessContextGetProperty
   MinifiProcessContextGetProcessorName
   MinifiProcessContextHasNonEmptyProperty
+  MinifiControllerServiceContextGetProperty
   MinifiLoggerSetMaxLogSize
   MinifiLoggerLogString
   MinifiLoggerShouldLog

Reply via email to