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 2494252f09793c3125c3e0ff396c7e1c56070114
Author: Martin Zink <[email protected]>
AuthorDate: Mon Jan 26 18:12:19 2026 +0100

    MINIFICPP-2708 Controller Service C API
---
 Extensions.md                                      |   4 +-
 core-framework/include/agent/agent_docs.h          |  13 +-
 .../core/controller/ControllerServiceBase.h        |   6 +-
 .../core/controller/ControllerServiceFactoryImpl.h |   4 +-
 .../aws/tests/MultipartUploadStateStorageTest.cpp  |   2 +-
 .../controllers/NetworkPrioritizerService.h        |   2 +-
 .../include/core/controller/ControllerService.h    |   9 +-
 libminifi/include/utils/CControllerService.h       | 112 +++++++++++++++
 libminifi/include/utils/CProcessor.h               |   9 +-
 libminifi/src/controllers/SSLContextService.cpp    |   2 +-
 libminifi/src/minifi-c.cpp                         | 150 +++++++++++++++++++--
 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       |   7 +-
 ...trollerServiceApi.h => ControllerServiceType.h} |   6 +-
 ...inition.h => ControllerServiceTypeDefinition.h} |   2 +-
 .../core/controller/ControllerServiceDescriptor.h  |   1 +
 .../core/controller/ControllerServiceFactory.h     |   5 +-
 minifi-api/minifi-c-api.def                        |   3 +
 25 files changed, 347 insertions(+), 60 deletions(-)

diff --git a/Extensions.md b/Extensions.md
index c002c96ce..d0d402bf1 100644
--- a/Extensions.md
+++ b/Extensions.md
@@ -77,7 +77,9 @@ extern "C" void MinifiInitCppExtension(MinifiExtension* 
extension, MinifiConfig*
     .deinit = nullptr,
     .user_data = nullptr,
     .processors_count = 0,
-    .processors_ptr = nullptr
+    .processors_ptr = nullptr,
+    .controller_services_count = 0,
+    .controller_services_ptr = nullptr,
   };
   minifi::utils::MinifiCreateCppExtension(extension, &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 99c7f2a71..f0880cb4f 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/ControllerServiceHandle.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"
 
 #define ADD_COMMON_VIRTUAL_FUNCTIONS_FOR_CONTROLLER_SERVICES \
   bool supportsDynamicProperties() const override { return 
SupportsDynamicProperties; }
@@ -96,7 +96,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/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/libminifi/include/controllers/NetworkPrioritizerService.h 
b/libminifi/include/controllers/NetworkPrioritizerService.h
index f893a9f68..684a72ce9 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 a4c26f547..561e41aee 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 impl_->supportsDynamicProperties();
   }
 
-  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..ca809b5cb
--- /dev/null
+++ b/libminifi/include/utils/CControllerService.h
@@ -0,0 +1,112 @@
+/**
+* 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 name;
+
+  std::vector<core::Property> class_properties;
+
+  MinifiControllerServiceCallbacks callbacks;
+};
+
+class CControllerService final : public 
core::controller::ControllerServiceApi, public 
core::controller::ControllerServiceHandle {
+ 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_);
+  }
+
+  [[nodiscard]] bool supportsDynamicProperties() const override {
+    return false;
+  }
+
+  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::ControllerServiceHandle>>&) 
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_);
+  }
+
+  ControllerServiceHandle* getControllerServiceHandle() 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 057d2e59d..e6424ead5 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 dccdadeed..c0b02d085 100644
--- a/libminifi/src/controllers/SSLContextService.cpp
+++ b/libminifi/src/controllers/SSLContextService.cpp
@@ -596,7 +596,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 bf9c5e84c..69e9ff935 100644
--- a/libminifi/src/minifi-c.cpp
+++ b/libminifi/src/minifi-c.cpp
@@ -36,12 +36,17 @@
 #include "minifi-cpp/core/logging/Logger.h"
 #include "minifi-cpp/core/state/PublishedMetricProvider.h"
 #include "utils/CProcessor.h"
+#include "utils/CControllerService.h"
 #include "utils/PropertyErrors.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_;
+};
+
 }  // namespace
 
 namespace org::apache::nifi::minifi::utils {
@@ -221,6 +257,32 @@ void useCProcessorClassDescription(const 
MinifiProcessorClassDefinition& class_d
   fn(description, c_class_description);
 }
 
+void useCControllerServiceClassDescription(const 
MinifiControllerServiceClassDefinition& class_description,
+    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{
+    .name = name_segments.back(),
+    .class_properties = properties,
+    .callbacks = class_description.callbacks
+  };
+  fn(description, c_class_description);
+}
 }  // namespace org::apache::nifi::minifi::utils
 
 extern "C" {
@@ -233,7 +295,7 @@ MinifiExtension* 
MinifiCreateExtension(MinifiExtensionContext* extension_context
     .name = extension_name,
     .version = toString(extension_create_info->version)
   };
-  auto* extension = 
reinterpret_cast<org::apache::nifi::minifi::core::extension::Extension::Context*>(extension_context)->create(org::apache::nifi::minifi::core::extension::Extension::Info{
+  auto* extension = 
reinterpret_cast<minifi::core::extension::Extension::Context*>(extension_context)->create(org::apache::nifi::minifi::core::extension::Extension::Info{
     .name = toString(extension_create_info->name),
     .version = toString(extension_create_info->version),
     .deinit = extension_create_info->deinit,
@@ -245,14 +307,14 @@ MinifiExtension* 
MinifiCreateExtension(MinifiExtensionContext* extension_context
   return MINIFI_NULL;
 }
 
-MinifiStatus MinifiRegisterProcessor(MinifiExtension* extension_handle, const 
MinifiProcessorClassDefinition* processor) {
-  gsl_Assert(extension_handle);
+MinifiStatus MinifiRegisterProcessor(MinifiExtension* extension, const 
MinifiProcessorClassDefinition* processor) {
+  gsl_Assert(extension);
   gsl_Assert(processor);
-  auto extension_info = 
reinterpret_cast<org::apache::nifi::minifi::core::extension::Extension*>(extension_handle)->getInfo();
+  auto extension_info = 
reinterpret_cast<org::apache::nifi::minifi::core::extension::Extension*>(extension)->getInfo();
   if (!extension_info) {
     return MINIFI_STATUS_UNKNOWN_ERROR;
   }
-  minifi::BundleIdentifier bundle{
+  const minifi::BundleIdentifier bundle{
     .name = extension_info->name,
     .version = extension_info->version
   };
@@ -266,6 +328,28 @@ MinifiStatus MinifiRegisterProcessor(MinifiExtension* 
extension_handle, const Mi
   return MINIFI_STATUS_SUCCESS;
 }
 
+MinifiStatus MinifiRegisterControllerService(MinifiExtension* extension, const 
MinifiControllerServiceClassDefinition* controller_service) {
+  gsl_Assert(extension);
+  gsl_Assert(controller_service);
+  auto extension_info = 
reinterpret_cast<minifi::core::extension::Extension*>(extension)->getInfo();
+  if (!extension_info) {
+    return MINIFI_STATUS_UNKNOWN_ERROR;
+  }
+  const minifi::BundleIdentifier bundle{
+    .name = extension_info->name,
+    .version = extension_info->version
+  };
+  auto& bundle_components = 
minifi::ClassDescriptionRegistry::getMutableClassDescriptions()[bundle];
+  minifi::utils::useCControllerServiceClassDescription(*controller_service, 
[&] (const auto& description, const auto& c_class_description) {
+    
minifi::core::ClassLoader::getDefaultClassLoader().getClassLoader(extension_info->name).registerClass(
+      c_class_description.name,
+      std::make_unique<CControllerServiceFactory>(extension_info->name, 
toString(controller_service->full_name), c_class_description));
+    bundle_components.controller_services.emplace_back(description);
+  });
+  return MINIFI_STATUS_SUCCESS;
+}
+
+
 MinifiExtension* MINIFI_CREATE_EXTENSION_FN(MinifiExtensionContext* 
extension_context, const MinifiExtensionCreateInfo* extension_create_info) {
   return MinifiCreateExtension(extension_context, extension_create_info);
 }
@@ -276,7 +360,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())) {
@@ -297,10 +381,7 @@ void MinifiConfigGet(MinifiExtensionContext* 
extension_context, MinifiStringView
   gsl_Assert(extension_context);
   auto value = 
reinterpret_cast<org::apache::nifi::minifi::core::extension::Extension::Context*>(extension_context)->config->get(toString(key));
   if (value) {
-    cb(user_ctx, MinifiStringView{
-      .data = value->data(),
-      .length = value->length()
-    });
+    cb(user_ctx, minifiStringView(*value));
   }
 }
 
@@ -444,7 +525,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;
 }
 
@@ -453,8 +534,53 @@ 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,
+    const MinifiStringView controller_service_name,
+    const MinifiStringView controller_service_type,
+    void** controller_service_out) {
+  if (!controller_service_out) {
+    return MINIFI_STATUS_UNKNOWN_ERROR;
+  }
+
+  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_VALIDATION_FAILED;
+  }
+  if (const minifi::utils::CControllerService* c_controller_service = 
dynamic_cast<minifi::utils::CControllerService*>(&*service_shared_ptr)) {
+    const auto class_description = c_controller_service->getClassDescription();
+    if (class_description.name == toStringView(controller_service_type)) {
+      *controller_service_out = c_controller_service->getImpl();
+      return MINIFI_STATUS_SUCCESS;
+    }
+  }
+  return MINIFI_STATUS_VALIDATION_FAILED;
+}
+
+
 }  // extern "C"
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 7f541c1db..941ec8b73 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 controller_service_impl = 
std::make_unique<T>(core::controller::ControllerServiceMetadata{
+  auto controller_service_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 86dc7b407..b689ce7ad 100644
--- a/minifi-api/include/minifi-c/minifi-c.h
+++ b/minifi-api/include/minifi-c/minifi-c.h
@@ -100,6 +100,8 @@ typedef struct MinifiExtensionContext 
MinifiExtensionContext;
 typedef struct MinifiPublishedMetrics MinifiPublishedMetrics;
 typedef struct MinifiAgent MinifiAgent;
 
+typedef struct MinifiControllerServiceContext MinifiControllerServiceContext;
+
 typedef enum MinifiStatus : uint32_t {
   MINIFI_STATUS_SUCCESS = 0,
   MINIFI_STATUS_UNKNOWN_ERROR = 1,
@@ -153,6 +155,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*);
@@ -164,6 +172,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;
@@ -183,6 +198,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;
@@ -194,12 +219,17 @@ MinifiExtension* 
MINIFI_CREATE_EXTENSION_FN(MinifiExtensionContext* extension_co
 
 MinifiStatus MinifiRegisterProcessor(MinifiExtension* extension, const 
MinifiProcessorClassDefinition* processor);
 
+MinifiStatus MinifiRegisterControllerService(MinifiExtension* extension, const 
MinifiControllerServiceClassDefinition* controller_service);
+
 MINIFI_OWNED MinifiPublishedMetrics* MinifiPublishedMetricsCreate(size_t 
count, const MinifiStringView* metric_names, const double* metric_values);
 
 MinifiStatus MinifiProcessContextGetProperty(MinifiProcessContext* context, 
MinifiStringView property_name, MinifiFlowFile* flowfile,
                                              void(*cb)(void* user_ctx, 
MinifiStringView property_value), void* user_ctx);
 MinifiBool MinifiProcessContextHasNonEmptyProperty(MinifiProcessContext* 
context, MinifiStringView property_name);
 
+MinifiStatus MinifiProcessContextGetControllerService(
+    MinifiProcessContext* process_context, MinifiStringView 
controller_service_name, MinifiStringView controller_service_type, void** 
controller_service_out);
+
 void MinifiLoggerSetMaxLogSize(MinifiLogger*, int32_t);
 void MinifiLoggerLogString(MinifiLogger*, MinifiLogLevel, MinifiStringView);
 MinifiBool MinifiLoggerShouldLog(MinifiLogger*, MinifiLogLevel);
@@ -226,6 +256,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 61a759bed..781dfb735 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 db7c26737..dff30ce1c 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/ControllerServiceHandle.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::ControllerServiceHandle {
  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 10e17f536..9e131168a 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/ControllerServiceHandle.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::ControllerServiceHandle {
  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 bc21a2092..0c17e260b 100644
--- a/minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h
+++ b/minifi-api/include/minifi-cpp/controllers/SSLContextServiceInterface.h
@@ -16,13 +16,12 @@
  */
 #pragma once
 
-#include <iostream>
+#include <filesystem>
 #include <memory>
 #include <string>
 #include <utility>
-#include <filesystem>
 
-#include "minifi-cpp/core/ControllerServiceApiDefinition.h"
+#include "minifi-cpp/core/ControllerServiceTypeDefinition.h"
 #include "minifi-cpp/agent/agent_version.h"
 #include "minifi-cpp/core/controller/ControllerServiceHandle.h"
 
@@ -38,7 +37,7 @@ namespace org::apache::nifi::minifi::controllers {
  */
 class SSLContextServiceInterface : public 
core::controller::ControllerServiceHandle {
  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/minifi-c-api.def b/minifi-api/minifi-c-api.def
index a22f8c696..9fabf206d 100644
--- a/minifi-api/minifi-c-api.def
+++ b/minifi-api/minifi-c-api.def
@@ -2,9 +2,12 @@ LIBRARY core-minifi.dll
 EXPORTS
   MinifiCreateExtension
   MinifiRegisterProcessor
+  MinifiRegisterControllerService
   MinifiPublishedMetricsCreate
+  MinifiProcessContextGetControllerService
   MinifiProcessContextGetProperty
   MinifiProcessContextHasNonEmptyProperty
+  MinifiControllerServiceContextGetProperty
   MinifiLoggerSetMaxLogSize
   MinifiLoggerLogString
   MinifiLoggerShouldLog


Reply via email to