This is an automated email from the ASF dual-hosted git repository.
martinzink pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
The following commit(s) were added to refs/heads/main by this push:
new 8be29c104 MINIFICPP-2885 Allow explictily unsetting properties with
default value (#2241)
8be29c104 is described below
commit 8be29c10489631bba464fc8c09f012659b08403a
Author: Martin Zink <[email protected]>
AuthorDate: Tue Aug 25 14:10:20 2026 +0200
MINIFICPP-2885 Allow explictily unsetting properties with default value
(#2241)
---
.../ubuntu_22_04_clang_arm_manifest.json | 45 +++++
.../include/core/ConfigurableComponentImpl.h | 1 +
.../src/core/ConfigurableComponentImpl.cpp | 10 +
.../stable-api-testing/ExtensionInitializer.cpp | 2 +
extensions/stable-api-testing/PropertyTester.h | 97 +++++++++
.../tests/PropertyTesterTests.cpp | 221 +++++++++++++++++++++
.../src/core/flow/StructuredConfiguration.cpp | 21 +-
.../resources/TestC2DescribeCoreComponentState.yml | 4 +
.../minifi-cpp/core/ConfigurableComponent.h | 1 +
minifi-api/include/minifi-cpp/core/Property.h | 1 +
10 files changed, 400 insertions(+), 3 deletions(-)
diff --git a/.github/references/ubuntu_22_04_clang_arm_manifest.json
b/.github/references/ubuntu_22_04_clang_arm_manifest.json
index 87d17440d..2d71ae28c 100644
--- a/.github/references/ubuntu_22_04_clang_arm_manifest.json
+++ b/.github/references/ubuntu_22_04_clang_arm_manifest.json
@@ -8415,6 +8415,51 @@
"bundles": {
"componentManifest": {
"processors": [
+ {
+ "propertyDescriptors": {
+ "OptionalPropertyWithDefaultValue": {
+ "name": "OptionalPropertyWithDefaultValue",
+ "description": "Test
OptionalPropertyWithDefaultValue",
+ "validator": "VALID",
+ "required": "false",
+ "sensitive": "false",
+ "expressionLanguageScope": "NONE",
+ "defaultValue": "default_val"
+ },
+ "OptionalPropertyWithoutDefaultValue": {
+ "name": "OptionalPropertyWithoutDefaultValue",
+ "description": "Test
OptionalPropertyWithoutDefaultValue",
+ "validator": "VALID",
+ "required": "false",
+ "sensitive": "false",
+ "expressionLanguageScope": "NONE"
+ },
+ "RequiredPropertyWithDefaultValue": {
+ "name": "RequiredPropertyWithDefaultValue",
+ "description": "Test
RequiredPropertyWithDefaultValue",
+ "validator": "VALID",
+ "required": "true",
+ "sensitive": "false",
+ "expressionLanguageScope": "NONE",
+ "defaultValue": "default_val"
+ },
+ "RequiredPropertyWithoutDefaultValue": {
+ "name": "RequiredPropertyWithoutDefaultValue",
+ "description": "Test
RequiredPropertyWithoutDefaultValue",
+ "validator": "VALID",
+ "required": "true",
+ "sensitive": "false",
+ "expressionLanguageScope": "NONE"
+ }
+ },
+ "inputRequirement": "INPUT_FORBIDDEN",
+ "isSingleThreaded": "true",
+ "supportedRelationships": [],
+ "typeDescription": "Test processor to test the parsing of
properties in the flow configuration",
+ "supportsDynamicRelationships": "false",
+ "supportsDynamicProperties": "false",
+ "type": "org.apache.nifi.minifi.api_testing.PropertyTester"
+ },
{
"propertyDescriptors": {
"Can fly service": {
diff --git a/core-framework/include/core/ConfigurableComponentImpl.h
b/core-framework/include/core/ConfigurableComponentImpl.h
index 90725d271..577c125b4 100644
--- a/core-framework/include/core/ConfigurableComponentImpl.h
+++ b/core-framework/include/core/ConfigurableComponentImpl.h
@@ -33,6 +33,7 @@ class ConfigurableComponentImpl : public virtual
ConfigurableComponent {
[[nodiscard]] std::expected<std::string, std::error_code>
getProperty(std::string_view name) const override;
std::expected<void, std::error_code> setProperty(std::string_view name,
std::string value) override;
std::expected<void, std::error_code> clearProperty(std::string_view name)
override;
+ std::expected<void, std::error_code>
clearPropertyDefaultValue(std::string_view name) override;
[[nodiscard]] std::expected<std::string, std::error_code>
getDynamicProperty(std::string_view name) const override;
std::expected<void, std::error_code> setDynamicProperty(std::string name,
std::string value) override;
diff --git a/core-framework/src/core/ConfigurableComponentImpl.cpp
b/core-framework/src/core/ConfigurableComponentImpl.cpp
index 1dd09d1e1..924af40ff 100644
--- a/core-framework/src/core/ConfigurableComponentImpl.cpp
+++ b/core-framework/src/core/ConfigurableComponentImpl.cpp
@@ -67,6 +67,16 @@ std::expected<void, std::error_code>
ConfigurableComponentImpl::clearProperty(co
return {};
}
+std::expected<void, std::error_code>
ConfigurableComponentImpl::clearPropertyDefaultValue(const std::string_view
name) {
+ const std::lock_guard<std::mutex> lock(configuration_mutex_);
+ const auto it = supported_properties_.find(name);
+ if (it == supported_properties_.end()) { return
std::unexpected{PropertyErrorCode::NotSupportedProperty}; }
+ Property& prop = it->second;
+
+ prop.clearDefaultValue();
+ return {};
+}
+
std::expected<void, std::error_code>
ConfigurableComponentImpl::appendProperty(const std::string_view name,
std::string value) {
const std::lock_guard<std::mutex> lock(configuration_mutex_);
const auto it = supported_properties_.find(name);
diff --git a/extensions/stable-api-testing/ExtensionInitializer.cpp
b/extensions/stable-api-testing/ExtensionInitializer.cpp
index 9150b6e20..d2c58764d 100644
--- a/extensions/stable-api-testing/ExtensionInitializer.cpp
+++ b/extensions/stable-api-testing/ExtensionInitializer.cpp
@@ -16,6 +16,7 @@
*/
#include "AnimalControllerServices.h"
+#include "PropertyTester.h"
#include "ZooProcessor.h"
#include "api/core/Resource.h"
#include "api/utils/minifi-c-utils.h"
@@ -35,5 +36,6 @@ CEXTENSIONAPI void
minifi_init_extension(minifi_extension_context* extension_con
.user_data = nullptr};
auto* extension = minifi_register_extension(extension_context,
&extension_definition);
minifi::api::core::registerProcessors<minifi::api_testing::ZooProcessor>(extension);
+
minifi::api::core::registerProcessors<minifi::api_testing::PropertyTester>(extension);
minifi::api::core::registerControllerServices<minifi::api_testing::DogController,
minifi::api_testing::DuckController>(extension);
}
diff --git a/extensions/stable-api-testing/PropertyTester.h
b/extensions/stable-api-testing/PropertyTester.h
new file mode 100644
index 000000000..93f421815
--- /dev/null
+++ b/extensions/stable-api-testing/PropertyTester.h
@@ -0,0 +1,97 @@
+/**
+ * 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 "api/core/ProcessorImpl.h"
+#include "api/utils/Export.h"
+#include "api/utils/ProcessorConfigUtils.h"
+#include "core/PropertyDefinitionBuilder.h"
+#include "minifi-api.h"
+#include "minifi-cpp/core/Annotation.h"
+
+namespace org::apache::nifi::minifi::api_testing {
+
+class PropertyTester : public api::core::ProcessorImpl {
+ public:
+ EXTENSIONAPI static constexpr const char* Description = "Test processor to
test the parsing of properties in the flow configuration";
+
+ EXTENSIONAPI static constexpr auto OptionalPropertyWithDefaultValue =
+
core::PropertyDefinitionBuilder<>::createProperty("OptionalPropertyWithDefaultValue")
+ .withDescription("Test OptionalPropertyWithDefaultValue")
+ .withDefaultValue("default_val")
+ .isRequired(false)
+ .build();
+
+ EXTENSIONAPI static constexpr auto OptionalPropertyWithoutDefaultValue =
+
core::PropertyDefinitionBuilder<>::createProperty("OptionalPropertyWithoutDefaultValue")
+ .withDescription("Test OptionalPropertyWithoutDefaultValue")
+ .isRequired(false)
+ .build();
+
+ EXTENSIONAPI static constexpr auto RequiredPropertyWithDefaultValue =
+
core::PropertyDefinitionBuilder<>::createProperty("RequiredPropertyWithDefaultValue")
+ .withDescription("Test RequiredPropertyWithDefaultValue")
+ .withDefaultValue("default_val")
+ .isRequired(true)
+ .build();
+
+ EXTENSIONAPI static constexpr auto RequiredPropertyWithoutDefaultValue =
+
core::PropertyDefinitionBuilder<>::createProperty("RequiredPropertyWithoutDefaultValue")
+ .withDescription("Test RequiredPropertyWithoutDefaultValue")
+ .isRequired(true)
+ .build();
+
+ EXTENSIONAPI static constexpr auto Properties =
std::to_array<core::PropertyReference>(
+ {OptionalPropertyWithDefaultValue, OptionalPropertyWithoutDefaultValue,
RequiredPropertyWithDefaultValue, RequiredPropertyWithoutDefaultValue});
+ EXTENSIONAPI static constexpr auto Relationships =
std::array<core::RelationshipDefinition, 0>{};
+ EXTENSIONAPI static constexpr bool SupportsDynamicProperties = false;
+ EXTENSIONAPI static constexpr bool SupportsDynamicRelationships = false;
+ EXTENSIONAPI static constexpr core::annotation::Input InputRequirement =
core::annotation::Input::INPUT_FORBIDDEN;
+ EXTENSIONAPI static constexpr bool IsSingleThreaded = true;
+
+ using ProcessorImpl::ProcessorImpl;
+
+ protected:
+ minifi_status onTriggerImpl(api::core::ProcessContext& process_context,
api::core::ProcessSession&) override {
+ {
+ const std::optional<std::string> optional_value_with_default =
api::utils::parseOptionalProperty(process_context,
+ OptionalPropertyWithDefaultValue);
+ logger_->log_critical("OptionalPropertyWithDefaultValue: {}",
optional_value_with_default);
+ }
+ {
+ const std::optional<std::string> optional_value_without_default =
api::utils::parseOptionalProperty(process_context,
+ OptionalPropertyWithoutDefaultValue);
+ logger_->log_critical("OptionalPropertyWithoutDefaultValue: {}",
optional_value_without_default);
+ }
+ {
+ const std::string required_value_with_default =
api::utils::parseProperty(process_context, RequiredPropertyWithDefaultValue);
+ logger_->log_critical("RequiredPropertyWithDefaultValue: {}",
required_value_with_default);
+ }
+ {
+ const std::string required_value_without_default =
api::utils::parseProperty(process_context, RequiredPropertyWithoutDefaultValue);
+ logger_->log_critical("RequiredPropertyWithoutDefaultValue: {}",
required_value_without_default);
+ }
+
+ return MINIFI_STATUS_SUCCESS;
+ }
+ minifi_status onScheduleImpl(api::core::ProcessContext&) override {
+ return MINIFI_STATUS_SUCCESS;
+ }
+};
+
+} // namespace org::apache::nifi::minifi::api_testing
diff --git a/extensions/stable-api-testing/tests/PropertyTesterTests.cpp
b/extensions/stable-api-testing/tests/PropertyTesterTests.cpp
new file mode 100644
index 000000000..3aacdb2ef
--- /dev/null
+++ b/extensions/stable-api-testing/tests/PropertyTesterTests.cpp
@@ -0,0 +1,221 @@
+/**
+ *
+ * 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.
+ */
+
+#include "core/flow/AdaptiveConfiguration.h"
+#include "unit/Catch.h"
+#include "unit/ConfigurationTestController.h"
+#include "unit/TestBase.h"
+#include "unit/TestUtils.h"
+
+using namespace std::literals::chrono_literals;
+
+TEST_CASE("Required property without Properties Entry (adaptive yaml)") {
+ const ConfigurationTestController controller;
+ core::flow::AdaptiveConfiguration config{controller.getContext()};
+ const auto config_yaml = R"(
+MiNiFi Config Version: 3
+Flow Controller:
+ name: MiNiFi Flow
+Processors:
+ - name: My processor
+ id: 00000000-0000-0000-0000-000000000001
+ class: PropertyTester
+Connections: [ ]
+Remote Process Groups: [ ]
+)";
+ REQUIRE_THROWS(config.getRootFromPayload(config_yaml));
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(100ms,
+ "[error] Error while processing configuration file: Unable to parse
configuration file for component named 'My processor' because required "
+ "property 'RequiredPropertyWithoutDefaultValue' is not set"));
+}
+
+TEST_CASE("Required property without Properties Entry (adaptive json)") {
+ const ConfigurationTestController controller;
+ core::flow::AdaptiveConfiguration config{controller.getContext()};
+ const auto config_json = R"(
+{
+ "Flow Controller": {"name": "root"},
+ "Processors": [
+ {
+ "id": "00000000-0000-0000-0000-000000000001",
+ "class": "PropertyTester",
+ "name": "My processor"
+ }
+ ],
+ "Connections": []
+}
+ )";
+ REQUIRE_THROWS(config.getRootFromPayload(config_json));
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(100ms,
+ "[error] Error while processing configuration file: Unable to parse
configuration file for component named 'My processor' because required "
+ "property 'RequiredPropertyWithoutDefaultValue' is not set"));
+}
+
+TEST_CASE("Explicitly unsetting required property (adaptive yaml)") {
+ const ConfigurationTestController controller;
+ core::flow::AdaptiveConfiguration config{controller.getContext()};
+ const auto config_yaml = R"(
+MiNiFi Config Version: 3
+Flow Controller:
+ name: MiNiFi Flow
+Processors:
+ - name: My processor
+ id: 00000000-0000-0000-0000-000000000001
+ class: PropertyTester
+ Properties:
+ RequiredPropertyWithDefaultValue: ~
+Connections: [ ]
+Remote Process Groups: [ ]
+)";
+ REQUIRE_THROWS(config.getRootFromPayload(config_yaml));
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(100ms,
+ "[error] Error while processing configuration file: Unable to parse
configuration file for component named 'My processor' because Can't "
+ "explicitly unset required property"));
+}
+
+TEST_CASE("Explicitly unsetting required property (adaptive json)") {
+ const ConfigurationTestController controller;
+ core::flow::AdaptiveConfiguration config{controller.getContext()};
+ const auto config_json = R"(
+{
+ "Flow Controller": {"name": "root"},
+ "Processors": [
+ {
+ "id": "00000000-0000-0000-0000-000000000001",
+ "class": "PropertyTester",
+ "name": "My processor",
+ "Properties": {
+ "RequiredPropertyWithDefaultValue": null,
+ }
+ }
+ ],
+ "Connections": []
+})";
+ REQUIRE_THROWS(config.getRootFromPayload(config_json));
+ REQUIRE(minifi::test::utils::verifyLogLinePresenceInPollTime(100ms,
+ "[error] Error while processing configuration file: Unable to parse
configuration file for component named 'My processor' because Can't "
+ "explicitly unset required property"));
+}
+
+TEST_CASE("Omitting optional property (adaptive yaml)") {
+ const ConfigurationTestController controller;
+ core::flow::AdaptiveConfiguration config{controller.getContext()};
+ const auto config_yaml = R"(
+MiNiFi Config Version: 3
+Flow Controller:
+ name: MiNiFi Flow
+Processors:
+ - name: My processor
+ id: 00000000-0000-0000-0000-000000000001
+ class: PropertyTester
+ Properties:
+ RequiredPropertyWithoutDefaultValue: 'bar'
+Connections: [ ]
+Remote Process Groups: [ ]
+)";
+ const auto root = config.getRootFromPayload(config_yaml);
+ REQUIRE(root);
+ const auto my_proc = root->findProcessorByName("My processor");
+ REQUIRE(my_proc);
+ const auto opt_val =
my_proc->getProperty("OptionalPropertyWithDefaultValue");
+ CHECK(opt_val == "default_val");
+}
+
+TEST_CASE("Omitting optional property (adaptive json)") {
+ const ConfigurationTestController controller;
+ core::flow::AdaptiveConfiguration config{controller.getContext()};
+ const auto config_json = R"(
+{
+ "Flow Controller": {"name": "root"},
+ "Processors": [
+ {
+ "id": "00000000-0000-0000-0000-000000000001",
+ "class": "PropertyTester",
+ "name": "My processor",
+ "Properties": {
+ "RequiredPropertyWithoutDefaultValue": "foo"
+ }
+ }
+ ],
+ "Connections": []
+})";
+ const auto root = config.getRootFromPayload(config_json);
+ REQUIRE(root);
+ const auto my_proc = root->findProcessorByName("My processor");
+ REQUIRE(my_proc);
+ const auto opt_val =
my_proc->getProperty("OptionalPropertyWithDefaultValue");
+ CHECK(opt_val == "default_val");
+}
+
+TEST_CASE("Explicitly unsetting optional property (adaptive yaml)") {
+ const ConfigurationTestController controller;
+ core::flow::AdaptiveConfiguration config{controller.getContext()};
+ const auto config_yaml = R"(
+MiNiFi Config Version: 3
+Flow Controller:
+ name: MiNiFi Flow
+Processors:
+ - name: My processor
+ id: 00000000-0000-0000-0000-000000000001
+ class: PropertyTester
+ Properties:
+ OptionalPropertyWithDefaultValue: ~
+ RequiredPropertyWithoutDefaultValue: 'foo'
+Connections: [ ]
+Remote Process Groups: [ ]
+)";
+ const auto root = config.getRootFromPayload(config_yaml);
+ REQUIRE(root);
+ const auto my_proc = root->findProcessorByName("My processor");
+ REQUIRE(my_proc);
+ const auto opt_val =
my_proc->getProperty("OptionalPropertyWithDefaultValue");
+ CHECK(!opt_val);
+ CHECK(!my_proc->getProperty("OptionalPropertyWithoutDefaultValue"));
+ CHECK(my_proc->getProperty("RequiredPropertyWithDefaultValue") ==
"default_val");
+ CHECK(my_proc->getProperty("RequiredPropertyWithoutDefaultValue") == "foo");
+}
+
+TEST_CASE("Explicitly unsetting optional property (adaptive json)") {
+ const ConfigurationTestController controller;
+ core::flow::AdaptiveConfiguration config{controller.getContext()};
+ const auto config_json = R"(
+{
+ "Flow Controller": {"name": "root"},
+ "Processors": [
+ {
+ "id": "00000000-0000-0000-0000-000000000001",
+ "class": "PropertyTester",
+ "name": "My processor",
+ "Properties": {
+ "OptionalPropertyWithDefaultValue": null,
+ "RequiredPropertyWithoutDefaultValue": "foo"
+ }
+ }
+ ],
+ "Connections": []
+})";
+ const auto root = config.getRootFromPayload(config_json);
+ REQUIRE(root);
+ const auto my_proc = root->findProcessorByName("My processor");
+ REQUIRE(my_proc);
+ const auto opt_val =
my_proc->getProperty("OptionalPropertyWithDefaultValue");
+ CHECK(!opt_val);
+ CHECK(!my_proc->getProperty("OptionalPropertyWithoutDefaultValue"));
+ CHECK(my_proc->getProperty("RequiredPropertyWithDefaultValue") ==
"default_val");
+ CHECK(my_proc->getProperty("RequiredPropertyWithoutDefaultValue") == "foo");
+}
diff --git a/libminifi/src/core/flow/StructuredConfiguration.cpp
b/libminifi/src/core/flow/StructuredConfiguration.cpp
index e94eb69b9..47324cb62 100644
--- a/libminifi/src/core/flow/StructuredConfiguration.cpp
+++ b/libminifi/src/core/flow/StructuredConfiguration.cpp
@@ -19,7 +19,6 @@
#include "core/flow/StructuredConfiguration.h"
#include <memory>
-#include <set>
#include <vector>
#include "Funnel.h"
@@ -29,8 +28,6 @@
#include "core/ReferenceParser.h"
#include "core/flow/CheckRequiredField.h"
#include "core/flow/StructuredConnectionParser.h"
-#include "core/state/Value.h"
-#include "utils/RegexUtils.h"
#include "utils/TimeUtil.h"
#include "utils/crypto/property_encryption/PropertyEncryptionUtils.h"
#include "utils/PropertyErrors.h"
@@ -244,6 +241,8 @@ void
StructuredConfiguration::parseParameterProvidersNode(const Node& parameter_
logger_->log_debug("Created Parameter Provider with UUID {} and name
{}", id, name);
if (Node propertiesNode =
parameter_provider_node[schema_.parameter_provider_properties]) {
parsePropertiesNode(propertiesNode, *parameter_provider, name,
nullptr);
+ } else {
+ validateComponentProperties(*parameter_provider, name, "");
}
} else {
logger_->log_debug("Could not locate {}", type);
@@ -384,6 +383,8 @@ void StructuredConfiguration::parseProcessorNode(const
Node& processors_node, co
// handle processor properties
if (Node propertiesNode = procNode[schema_.processor_properties]) {
parsePropertiesNode(propertiesNode, *processor, procCfg.name,
parentGroup->getParameterContext());
+ } else {
+ validateComponentProperties(*processor, procCfg.name, "");
}
// Take care of scheduling
@@ -666,6 +667,8 @@ void StructuredConfiguration::parseControllerServices(const
Node& controller_ser
if (auto controllerServiceImpl =
controller_service_node->getControllerServiceImplementation();
controllerServiceImpl) {
parsePropertiesNode(propertiesNode, *controllerServiceImpl, name,
parent_group->getParameterContext());
}
+ } else {
+ validateComponentProperties(*controller_service_node, name, "");
}
parent_group->addControllerService(controller_service_node->getName(),
controller_service_node, controller_service_node->getUUIDStr());
@@ -936,6 +939,18 @@ void
StructuredConfiguration::parsePropertyNodeElement(const std::string& proper
ParameterContext* parameter_context) {
logger_->log_trace("Encountered {}", property_name);
if (!property_value_node || property_value_node.isNull()) {
+ auto my_prop = component.getSupportedProperty(property_name);
+ if (!my_prop.has_value()) {
+ // Dynamic property fallback for previous workflow
+ return;
+ }
+ if (my_prop->getRequired()) {
+ raiseComponentError(component.getName(), "", fmt::format("Can't
explicitly unset required property: '{}'", property_name));
+ }
+ const auto prop_def_cleared =
component.clearPropertyDefaultValue(property_name);
+ if (!prop_def_cleared) {
+ raiseComponentError(component.getName(), "",
prop_def_cleared.error().message());
+ }
return;
}
if (property_value_node.isSequence()) {
diff --git a/libminifi/test/resources/TestC2DescribeCoreComponentState.yml
b/libminifi/test/resources/TestC2DescribeCoreComponentState.yml
index 03cf1a69c..8252ff947 100644
--- a/libminifi/test/resources/TestC2DescribeCoreComponentState.yml
+++ b/libminifi/test/resources/TestC2DescribeCoreComponentState.yml
@@ -29,6 +29,8 @@ Processors:
penalization period: 30 sec
yield period: 1 sec
run duration nanos: 0
+ Properties:
+ File to Tail: test.log
auto-terminated relationships list:
- success
- name: TailFile2
@@ -40,6 +42,8 @@ Processors:
penalization period: 30 sec
yield period: 1 sec
run duration nanos: 0
+ Properties:
+ File to Tail: test.log
auto-terminated relationships list:
- success
diff --git a/minifi-api/include/minifi-cpp/core/ConfigurableComponent.h
b/minifi-api/include/minifi-cpp/core/ConfigurableComponent.h
index 377903754..733294c8b 100644
--- a/minifi-api/include/minifi-cpp/core/ConfigurableComponent.h
+++ b/minifi-api/include/minifi-cpp/core/ConfigurableComponent.h
@@ -39,6 +39,7 @@ class ConfigurableComponent : public virtual CoreComponent {
virtual std::expected<void, std::error_code> setProperty(std::string_view
name, std::string value) = 0;
virtual std::expected<void, std::error_code> appendProperty(std::string_view
name, std::string value) = 0;
virtual std::expected<void, std::error_code> clearProperty(std::string_view
name) = 0;
+ virtual std::expected<void, std::error_code>
clearPropertyDefaultValue(std::string_view name) = 0;
[[nodiscard]] virtual std::expected<std::string, std::error_code>
getDynamicProperty(std::string_view name) const = 0;
virtual std::expected<void, std::error_code> setDynamicProperty(std::string
name, std::string value) = 0;
diff --git a/minifi-api/include/minifi-cpp/core/Property.h
b/minifi-api/include/minifi-cpp/core/Property.h
index d802b7221..8c7c4d686 100644
--- a/minifi-api/include/minifi-cpp/core/Property.h
+++ b/minifi-api/include/minifi-cpp/core/Property.h
@@ -56,6 +56,7 @@ class Property final {
std::vector<std::string> getAllowedValues() const { return allowed_values_; }
void setAllowedValues(std::vector<std::string> allowed_values) {
allowed_values_ = std::move(allowed_values); }
std::optional<std::string> getDefaultValue() const { return default_value_; }
+ void clearDefaultValue() { default_value_ = std::nullopt; }
std::string getName() const;
std::string getDisplayName() const;
std::vector<std::string> getAllowedTypes() const;