This is an automated email from the ASF dual-hosted git repository. lordgamez pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit fbd69e7e211b3f2fbd72d8ce806ac025aa63b6e0 Author: Ferenc Gerlits <fgerl...@gmail.com> AuthorDate: Wed Aug 9 14:50:53 2023 +0200 MINIFICPP-2164 Use a list of types for allowed types in PropertyDefinition Signed-off-by: Gabor Gyimesi <gamezb...@gmail.com> This closes #1626 --- extensions/elasticsearch/PostElasticsearch.h | 9 +- extensions/gcp/processors/GCSProcessor.h | 4 +- extensions/http-curl/processors/InvokeHTTP.h | 4 +- extensions/librdkafka/KafkaProcessorBase.h | 52 ++++++------ extensions/splunk/SplunkHECProcessor.h | 40 ++++----- extensions/standard-processors/processors/GetTCP.h | 4 +- .../standard-processors/processors/ListenSyslog.h | 4 +- .../standard-processors/processors/ListenTCP.h | 4 +- .../standard-processors/processors/PutFile.h | 2 +- extensions/standard-processors/processors/PutTCP.h | 98 +++++++++++----------- .../standard-processors/processors/TailFile.h | 4 +- .../tests/unit/YamlConfigurationTests.cpp | 8 +- libminifi/include/core/OutputAttributeDefinition.h | 4 +- libminifi/include/core/PropertyDefinition.h | 18 ++-- libminifi/include/core/PropertyDefinitionBuilder.h | 41 +++++---- libminifi/src/core/Property.cpp | 6 +- libminifi/test/unit/ComponentManifestTests.cpp | 4 +- libminifi/test/unit/TypeListTests.cpp | 61 ++++++++++++++ 18 files changed, 217 insertions(+), 150 deletions(-) diff --git a/extensions/elasticsearch/PostElasticsearch.h b/extensions/elasticsearch/PostElasticsearch.h index 367e35d21..ec213b982 100644 --- a/extensions/elasticsearch/PostElasticsearch.h +++ b/extensions/elasticsearch/PostElasticsearch.h @@ -53,16 +53,16 @@ class PostElasticsearch : public core::Processor { .withPropertyType(core::StandardPropertyTypes::UNSIGNED_LONG_TYPE) .withDefaultValue("100") .build(); - EXTENSIONAPI static constexpr auto ElasticCredentials = core::PropertyDefinitionBuilder<0, 1>::createProperty("Elasticsearch Credentials Provider Service") + EXTENSIONAPI static constexpr auto ElasticCredentials = core::PropertyDefinitionBuilder<>::createProperty("Elasticsearch Credentials Provider Service") .withDescription("The Controller Service used to obtain Elasticsearch credentials.") .isRequired(true) - .withAllowedTypes({core::className<ElasticsearchCredentialsControllerService>()}) + .withAllowedTypes<ElasticsearchCredentialsControllerService>() .build(); - EXTENSIONAPI static constexpr auto SSLContext = core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service") + EXTENSIONAPI static constexpr auto SSLContext = core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service") .withDescription("The SSL Context Service used to provide client certificate " "information for TLS/SSL (https) connections.") .isRequired(false) - .withAllowedTypes({core::className<minifi::controllers::SSLContextService>()}) + .withAllowedTypes<minifi::controllers::SSLContextService>() .build(); EXTENSIONAPI static constexpr auto Hosts = core::PropertyDefinitionBuilder<>::createProperty("Hosts") .withDescription("A comma-separated list of HTTP hosts that host Elasticsearch query nodes. Currently only supports a single host.") @@ -90,7 +90,6 @@ class PostElasticsearch : public core::Processor { Identifier }; - EXTENSIONAPI static constexpr auto Success = core::RelationshipDefinition{"success", "All flowfiles that succeed in being transferred into Elasticsearch go here."}; EXTENSIONAPI static constexpr auto Failure = core::RelationshipDefinition{"failure", "All flowfiles that fail for reasons unrelated to server availability go to this relationship."}; EXTENSIONAPI static constexpr auto Error = core::RelationshipDefinition{"error", "All flowfiles that Elasticsearch responded to with an error go to this relationship."}; diff --git a/extensions/gcp/processors/GCSProcessor.h b/extensions/gcp/processors/GCSProcessor.h index b54fbe691..8cfbe9c1d 100644 --- a/extensions/gcp/processors/GCSProcessor.h +++ b/extensions/gcp/processors/GCSProcessor.h @@ -39,10 +39,10 @@ class GCSProcessor : public core::Processor { logger_(std::move(logger)) { } - EXTENSIONAPI static constexpr auto GCPCredentials = core::PropertyDefinitionBuilder<0, 1>::createProperty("GCP Credentials Provider Service") + EXTENSIONAPI static constexpr auto GCPCredentials = core::PropertyDefinitionBuilder<>::createProperty("GCP Credentials Provider Service") .withDescription("The Controller Service used to obtain Google Cloud Platform credentials. Should be the name of a GCPCredentialsControllerService.") .isRequired(true) - .withAllowedTypes({core::className<GCPCredentialsControllerService>()}) + .withAllowedTypes<GCPCredentialsControllerService>() .build(); EXTENSIONAPI static constexpr auto NumberOfRetries = core::PropertyDefinitionBuilder<>::createProperty("Number of retries") .withDescription("How many retry attempts should be made before routing to the failure relationship.") diff --git a/extensions/http-curl/processors/InvokeHTTP.h b/extensions/http-curl/processors/InvokeHTTP.h index c9d291a34..99a6a8968 100644 --- a/extensions/http-curl/processors/InvokeHTTP.h +++ b/extensions/http-curl/processors/InvokeHTTP.h @@ -103,10 +103,10 @@ class InvokeHTTP : public core::Processor { EXTENSIONAPI static constexpr auto AttributesToSend = core::PropertyDefinitionBuilder<>::createProperty("Attributes to Send") .withDescription("Regular expression that defines which attributes to send as HTTP headers in the request. If not defined, no attributes are sent as headers.") .build(); - EXTENSIONAPI static constexpr auto SSLContext = core::PropertyDefinitionBuilder<0, 1, 0, 1>::createProperty("SSL Context Service") + EXTENSIONAPI static constexpr auto SSLContext = core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("SSL Context Service") .withDescription("The SSL Context Service used to provide client certificate information for TLS/SSL (https) connections.") .isRequired(false) - .withAllowedTypes({core::className<minifi::controllers::SSLContextService>()}) + .withAllowedTypes<minifi::controllers::SSLContextService>() .withExclusiveOfProperties({{{"Remote URL", "^http:.*$"}}}) .build(); EXTENSIONAPI static constexpr auto ProxyHost = core::PropertyDefinitionBuilder<>::createProperty("Proxy Host") diff --git a/extensions/librdkafka/KafkaProcessorBase.h b/extensions/librdkafka/KafkaProcessorBase.h index eecc3f2fc..6e88c6689 100644 --- a/extensions/librdkafka/KafkaProcessorBase.h +++ b/extensions/librdkafka/KafkaProcessorBase.h @@ -47,37 +47,37 @@ enum class SASLMechanismOption { class KafkaProcessorBase : public core::Processor { public: - EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service") - .withDescription("SSL Context Service Name") - .withAllowedTypes({core::className<minifi::controllers::SSLContextService>()}) - .build(); + EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service") + .withDescription("SSL Context Service Name") + .withAllowedTypes<minifi::controllers::SSLContextService>() + .build(); EXTENSIONAPI static constexpr auto SecurityProtocol = core::PropertyDefinitionBuilder<magic_enum::enum_count<kafka::SecurityProtocolOption>()>::createProperty("Security Protocol") - .withDescription("Protocol used to communicate with brokers. Corresponds to Kafka's 'security.protocol' property.") - .withDefaultValue(magic_enum::enum_name(kafka::SecurityProtocolOption::plaintext)) - .withAllowedValues(magic_enum::enum_names<kafka::SecurityProtocolOption>()) - .isRequired(true) - .build(); + .withDescription("Protocol used to communicate with brokers. Corresponds to Kafka's 'security.protocol' property.") + .withDefaultValue(magic_enum::enum_name(kafka::SecurityProtocolOption::plaintext)) + .withAllowedValues(magic_enum::enum_names<kafka::SecurityProtocolOption>()) + .isRequired(true) + .build(); EXTENSIONAPI static constexpr auto KerberosServiceName = core::PropertyDefinitionBuilder<>::createProperty("Kerberos Service Name") - .withDescription("Kerberos Service Name") - .build(); + .withDescription("Kerberos Service Name") + .build(); EXTENSIONAPI static constexpr auto KerberosPrincipal = core::PropertyDefinitionBuilder<>::createProperty("Kerberos Principal") - .withDescription("Kerberos Principal") - .build(); + .withDescription("Kerberos Principal") + .build(); EXTENSIONAPI static constexpr auto KerberosKeytabPath = core::PropertyDefinitionBuilder<>::createProperty("Kerberos Keytab Path") - .withDescription("The path to the location on the local filesystem where the kerberos keytab is located. Read permission on the file is required.") - .build(); + .withDescription("The path to the location on the local filesystem where the kerberos keytab is located. Read permission on the file is required.") + .build(); EXTENSIONAPI static constexpr auto SASLMechanism = core::PropertyDefinitionBuilder<magic_enum::enum_count<kafka::SASLMechanismOption>()>::createProperty("SASL Mechanism") - .withDescription("The SASL mechanism to use for authentication. Corresponds to Kafka's 'sasl.mechanism' property.") - .withDefaultValue(magic_enum::enum_name(kafka::SASLMechanismOption::GSSAPI)) - .withAllowedValues(magic_enum::enum_names<kafka::SASLMechanismOption>()) - .isRequired(true) - .build(); + .withDescription("The SASL mechanism to use for authentication. Corresponds to Kafka's 'sasl.mechanism' property.") + .withDefaultValue(magic_enum::enum_name(kafka::SASLMechanismOption::GSSAPI)) + .withAllowedValues(magic_enum::enum_names<kafka::SASLMechanismOption>()) + .isRequired(true) + .build(); EXTENSIONAPI static constexpr auto Username = core::PropertyDefinitionBuilder<>::createProperty("Username") - .withDescription("The username when the SASL Mechanism is sasl_plaintext") - .build(); + .withDescription("The username when the SASL Mechanism is sasl_plaintext") + .build(); EXTENSIONAPI static constexpr auto Password = core::PropertyDefinitionBuilder<>::createProperty("Password") - .withDescription("The password for the given username when the SASL Mechanism is sasl_plaintext") - .build(); + .withDescription("The password for the given username when the SASL Mechanism is sasl_plaintext") + .build(); EXTENSIONAPI static constexpr auto Properties = std::array<core::PropertyReference, 8>{ SSLContextService, SecurityProtocol, @@ -92,14 +92,14 @@ class KafkaProcessorBase : public core::Processor { KafkaProcessorBase(std::string name, const utils::Identifier& uuid, std::shared_ptr<core::logging::Logger> logger) : core::Processor(std::move(name), uuid), - logger_(logger) { + logger_(std::move(logger)) { } protected: virtual std::optional<utils::net::SslData> getSslData(core::ProcessContext& context) const; void setKafkaAuthenticationParameters(core::ProcessContext& context, gsl::not_null<rd_kafka_conf_t*> config); - kafka::SecurityProtocolOption security_protocol_; + kafka::SecurityProtocolOption security_protocol_{}; std::shared_ptr<core::logging::Logger> logger_; }; diff --git a/extensions/splunk/SplunkHECProcessor.h b/extensions/splunk/SplunkHECProcessor.h index e33a2bf92..bc885ac13 100644 --- a/extensions/splunk/SplunkHECProcessor.h +++ b/extensions/splunk/SplunkHECProcessor.h @@ -36,29 +36,29 @@ namespace org::apache::nifi::minifi::extensions::splunk { class SplunkHECProcessor : public core::Processor { public: EXTENSIONAPI static constexpr auto Hostname = core::PropertyDefinitionBuilder<>::createProperty("Hostname") - .withDescription("The ip address or hostname of the Splunk server.") - .isRequired(true) - .build(); + .withDescription("The ip address or hostname of the Splunk server.") + .isRequired(true) + .build(); EXTENSIONAPI static constexpr auto Port = core::PropertyDefinitionBuilder<>::createProperty("Port") - .withDescription("The HTTP Event Collector HTTP Port Number.") - .withPropertyType(core::StandardPropertyTypes::PORT_TYPE) - .withDefaultValue("8088") - .isRequired(true) - .build(); + .withDescription("The HTTP Event Collector HTTP Port Number.") + .withPropertyType(core::StandardPropertyTypes::PORT_TYPE) + .withDefaultValue("8088") + .isRequired(true) + .build(); EXTENSIONAPI static constexpr auto Token = core::PropertyDefinitionBuilder<>::createProperty("Token") - .withDescription("HTTP Event Collector token starting with the string Splunk. For example \'Splunk 1234578-abcd-1234-abcd-1234abcd\'") - .isRequired(true) - .build(); + .withDescription("HTTP Event Collector token starting with the string Splunk. For example \'Splunk 1234578-abcd-1234-abcd-1234abcd\'") + .isRequired(true) + .build(); EXTENSIONAPI static constexpr auto SplunkRequestChannel = core::PropertyDefinitionBuilder<>::createProperty("Splunk Request Channel") - .withDescription("Identifier of the used request channel.") - .isRequired(true) - .build(); - EXTENSIONAPI static constexpr auto SSLContext = core::PropertyDefinitionBuilder<0, 1, 0, 1>::createProperty("SSL Context Service") - .withDescription("The SSL Context Service used to provide client certificate information for TLS/SSL (https) connections.") - .isRequired(false) - .withExclusiveOfProperties({{{"Hostname", "^http:.*$"}}}) - .withAllowedTypes({core::className<minifi::controllers::SSLContextService>()}) - .build(); + .withDescription("Identifier of the used request channel.") + .isRequired(true) + .build(); + EXTENSIONAPI static constexpr auto SSLContext = core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("SSL Context Service") + .withDescription("The SSL Context Service used to provide client certificate information for TLS/SSL (https) connections.") + .isRequired(false) + .withExclusiveOfProperties({{{"Hostname", "^http:.*$"}}}) + .withAllowedTypes<minifi::controllers::SSLContextService>() + .build(); EXTENSIONAPI static constexpr auto Properties = std::array<core::PropertyReference, 5>{ Hostname, Port, diff --git a/extensions/standard-processors/processors/GetTCP.h b/extensions/standard-processors/processors/GetTCP.h index 5846956be..184da62df 100644 --- a/extensions/standard-processors/processors/GetTCP.h +++ b/extensions/standard-processors/processors/GetTCP.h @@ -69,9 +69,9 @@ class GetTCP : public core::Processor { .withDescription("A comma delimited list of the endpoints to connect to. The format should be <server_address>:<port>.") .isRequired(true) .build(); - EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service") + EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service") .withDescription("SSL Context Service Name") - .withAllowedTypes({core::className<minifi::controllers::SSLContextService>()}) + .withAllowedTypes<minifi::controllers::SSLContextService>() .build(); EXTENSIONAPI static constexpr auto MessageDelimiter = core::PropertyDefinitionBuilder<>::createProperty("Message Delimiter") .withDescription("Character that denotes the end of the message.") diff --git a/extensions/standard-processors/processors/ListenSyslog.h b/extensions/standard-processors/processors/ListenSyslog.h index 3f975cb2c..0f172e35e 100644 --- a/extensions/standard-processors/processors/ListenSyslog.h +++ b/extensions/standard-processors/processors/ListenSyslog.h @@ -75,10 +75,10 @@ class ListenSyslog : public NetworkListenerProcessor { .withPropertyType(core::StandardPropertyTypes::UNSIGNED_LONG_TYPE) .withDefaultValue("10000") .build(); - EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service") + EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service") .withDescription("The Controller Service to use in order to obtain an SSL Context. If this property is set, messages will be received over a secure connection. " "This Property is only considered if the <Protocol> Property has a value of \"TCP\".") - .withAllowedTypes({core::className<minifi::controllers::SSLContextService>()}) + .withAllowedTypes<minifi::controllers::SSLContextService>() .build(); EXTENSIONAPI static constexpr auto ClientAuth = core::PropertyDefinitionBuilder<magic_enum::enum_count<utils::net::ClientAuthOption>()>::createProperty("Client Auth") .withDescription("The client authentication policy to use for the SSL Context. Only used if an SSL Context Service is provided.") diff --git a/extensions/standard-processors/processors/ListenTCP.h b/extensions/standard-processors/processors/ListenTCP.h index 9f096838a..79d13fa1b 100644 --- a/extensions/standard-processors/processors/ListenTCP.h +++ b/extensions/standard-processors/processors/ListenTCP.h @@ -60,9 +60,9 @@ class ListenTCP : public NetworkListenerProcessor { .withDefaultValue("10000") .isRequired(true) .build(); - EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service") + EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service") .withDescription("The Controller Service to use in order to obtain an SSL Context. If this property is set, messages will be received over a secure connection.") - .withAllowedTypes({core::className<minifi::controllers::SSLContextService>()}) + .withAllowedTypes<minifi::controllers::SSLContextService>() .build(); EXTENSIONAPI static constexpr auto ClientAuth = core::PropertyDefinitionBuilder<magic_enum::enum_count<utils::net::ClientAuthOption>()>::createProperty("Client Auth") .withDescription("The client authentication policy to use for the SSL Context. Only used if an SSL Context Service is provided.") diff --git a/extensions/standard-processors/processors/PutFile.h b/extensions/standard-processors/processors/PutFile.h index 26d49571b..9067a1f6c 100644 --- a/extensions/standard-processors/processors/PutFile.h +++ b/extensions/standard-processors/processors/PutFile.h @@ -71,7 +71,7 @@ class PutFile : public core::Processor { .withAllowedValues({CONFLICT_RESOLUTION_STRATEGY_FAIL, CONFLICT_RESOLUTION_STRATEGY_IGNORE, CONFLICT_RESOLUTION_STRATEGY_REPLACE}) .withDefaultValue(CONFLICT_RESOLUTION_STRATEGY_FAIL) .build(); - EXTENSIONAPI static constexpr auto CreateDirs = core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Create Missing Directories") + EXTENSIONAPI static constexpr auto CreateDirs = core::PropertyDefinitionBuilder<0, 1>::createProperty("Create Missing Directories") .withDescription("If true, then missing destination directories will be created. If false, flowfiles are penalized and sent to failure.") .withDefaultValue("true") .isRequired(true) diff --git a/extensions/standard-processors/processors/PutTCP.h b/extensions/standard-processors/processors/PutTCP.h index 923f90a24..5063bae67 100644 --- a/extensions/standard-processors/processors/PutTCP.h +++ b/extensions/standard-processors/processors/PutTCP.h @@ -63,55 +63,55 @@ class PutTCP final : public core::Processor { "An optional \"Connection Per FlowFile\" parameter can be specified to change the behaviour so that each FlowFiles content is transmitted over a single TCP connection " "which is closed after the FlowFile has been sent."; -EXTENSIONAPI static constexpr auto Hostname = core::PropertyDefinitionBuilder<>::createProperty("Hostname") - .withDescription("The ip address or hostname of the destination.") - .withDefaultValue("localhost") - .isRequired(true) - .supportsExpressionLanguage(true) - .build(); -EXTENSIONAPI static constexpr auto Port = core::PropertyDefinitionBuilder<>::createProperty("Port") - .withDescription("The port or service on the destination.") - .isRequired(true) - .supportsExpressionLanguage(true) - .build(); -EXTENSIONAPI static constexpr auto IdleConnectionExpiration = core::PropertyDefinitionBuilder<>::createProperty("Idle Connection Expiration") - .withDescription("The amount of time a connection should be held open without being used before closing the connection. A value of 0 seconds will disable this feature.") - .withPropertyType(core::StandardPropertyTypes::TIME_PERIOD_TYPE) - .withDefaultValue("15 seconds") - .isRequired(true) - .supportsExpressionLanguage(true) - .build(); -EXTENSIONAPI static constexpr auto Timeout = core::PropertyDefinitionBuilder<>::createProperty("Timeout") - .withDescription("The timeout for connecting to and communicating with the destination.") - .withPropertyType(core::StandardPropertyTypes::TIME_PERIOD_TYPE) - .withDefaultValue("15 seconds") - .isRequired(true) - .supportsExpressionLanguage(true) - .build(); -EXTENSIONAPI static constexpr auto ConnectionPerFlowFile = core::PropertyDefinitionBuilder<>::createProperty("Connection Per FlowFile") - .withDescription("Specifies whether to send each FlowFile's content on an individual connection.") - .withPropertyType(core::StandardPropertyTypes::BOOLEAN_TYPE) - .withDefaultValue("false") - .isRequired(true) - .supportsExpressionLanguage(false) - .build(); -EXTENSIONAPI static constexpr auto OutgoingMessageDelimiter = core::PropertyDefinitionBuilder<>::createProperty("Outgoing Message Delimiter") - .withDescription("Specifies the delimiter to use when sending messages out over the same TCP stream. " - "The delimiter is appended to each FlowFile message that is transmitted over the stream so that the receiver can determine when one message ends and the next message begins. " - "Users should ensure that the FlowFile content does not contain the delimiter character to avoid errors.") - .isRequired(false) - .supportsExpressionLanguage(true) - .build(); -EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<0, 1>::createProperty("SSL Context Service") - .withDescription("The Controller Service to use in order to obtain an SSL Context. If this property is set, messages will be sent over a secure connection.") - .isRequired(false) - .withAllowedTypes({core::className<minifi::controllers::SSLContextService>()}) - .build(); -EXTENSIONAPI static constexpr auto MaxSizeOfSocketSendBuffer = core::PropertyDefinitionBuilder<>::createProperty("Max Size of Socket Send Buffer") - .withDescription("The maximum size of the socket send buffer that should be used. This is a suggestion to the Operating System to indicate how big the socket buffer should be.") - .isRequired(false) - .withPropertyType(core::StandardPropertyTypes::DATA_SIZE_TYPE) - .build(); + EXTENSIONAPI static constexpr auto Hostname = core::PropertyDefinitionBuilder<>::createProperty("Hostname") + .withDescription("The ip address or hostname of the destination.") + .withDefaultValue("localhost") + .isRequired(true) + .supportsExpressionLanguage(true) + .build(); + EXTENSIONAPI static constexpr auto Port = core::PropertyDefinitionBuilder<>::createProperty("Port") + .withDescription("The port or service on the destination.") + .isRequired(true) + .supportsExpressionLanguage(true) + .build(); + EXTENSIONAPI static constexpr auto IdleConnectionExpiration = core::PropertyDefinitionBuilder<>::createProperty("Idle Connection Expiration") + .withDescription("The amount of time a connection should be held open without being used before closing the connection. A value of 0 seconds will disable this feature.") + .withPropertyType(core::StandardPropertyTypes::TIME_PERIOD_TYPE) + .withDefaultValue("15 seconds") + .isRequired(true) + .supportsExpressionLanguage(true) + .build(); + EXTENSIONAPI static constexpr auto Timeout = core::PropertyDefinitionBuilder<>::createProperty("Timeout") + .withDescription("The timeout for connecting to and communicating with the destination.") + .withPropertyType(core::StandardPropertyTypes::TIME_PERIOD_TYPE) + .withDefaultValue("15 seconds") + .isRequired(true) + .supportsExpressionLanguage(true) + .build(); + EXTENSIONAPI static constexpr auto ConnectionPerFlowFile = core::PropertyDefinitionBuilder<>::createProperty("Connection Per FlowFile") + .withDescription("Specifies whether to send each FlowFile's content on an individual connection.") + .withPropertyType(core::StandardPropertyTypes::BOOLEAN_TYPE) + .withDefaultValue("false") + .isRequired(true) + .supportsExpressionLanguage(false) + .build(); + EXTENSIONAPI static constexpr auto OutgoingMessageDelimiter = core::PropertyDefinitionBuilder<>::createProperty("Outgoing Message Delimiter") + .withDescription("Specifies the delimiter to use when sending messages out over the same TCP stream. " + "The delimiter is appended to each FlowFile message that is transmitted over the stream so that the receiver can determine when one message ends and the next message begins. " + "Users should ensure that the FlowFile content does not contain the delimiter character to avoid errors.") + .isRequired(false) + .supportsExpressionLanguage(true) + .build(); + EXTENSIONAPI static constexpr auto SSLContextService = core::PropertyDefinitionBuilder<>::createProperty("SSL Context Service") + .withDescription("The Controller Service to use in order to obtain an SSL Context. If this property is set, messages will be sent over a secure connection.") + .isRequired(false) + .withAllowedTypes<minifi::controllers::SSLContextService>() + .build(); + EXTENSIONAPI static constexpr auto MaxSizeOfSocketSendBuffer = core::PropertyDefinitionBuilder<>::createProperty("Max Size of Socket Send Buffer") + .withDescription("The maximum size of the socket send buffer that should be used. This is a suggestion to the Operating System to indicate how big the socket buffer should be.") + .isRequired(false) + .withPropertyType(core::StandardPropertyTypes::DATA_SIZE_TYPE) + .build(); EXTENSIONAPI static constexpr auto Properties = std::array<core::PropertyReference, 8>{ Hostname, Port, diff --git a/extensions/standard-processors/processors/TailFile.h b/extensions/standard-processors/processors/TailFile.h index 809d80fdc..015eab7d9 100644 --- a/extensions/standard-processors/processors/TailFile.h +++ b/extensions/standard-processors/processors/TailFile.h @@ -179,9 +179,9 @@ class TailFile : public core::Processor { .withDefaultValue(magic_enum::enum_name(InitialStartPositions::BEGINNING_OF_FILE)) .withAllowedValues(magic_enum::enum_names<InitialStartPositions>()) .build(); - EXTENSIONAPI static constexpr auto AttributeProviderService = core::PropertyDefinitionBuilder<0, 1>::createProperty("Attribute Provider Service") + EXTENSIONAPI static constexpr auto AttributeProviderService = core::PropertyDefinitionBuilder<>::createProperty("Attribute Provider Service") .withDescription("Provides a list of key-value pair records which can be used in the Base Directory property using Expression Language. Requires Multiple file mode.") - .withAllowedTypes({core::className<minifi::controllers::AttributeProviderService>()}) + .withAllowedTypes<minifi::controllers::AttributeProviderService>() .build(); EXTENSIONAPI static constexpr auto BatchSize = core::PropertyDefinitionBuilder<>::createProperty("Batch Size") .withDescription("Maximum number of flowfiles emitted in a single trigger. If set to 0 all new content will be processed.") diff --git a/extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp b/extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp index be7a60c97..deac64ba4 100644 --- a/extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp +++ b/extensions/standard-processors/tests/unit/YamlConfigurationTests.cpp @@ -585,7 +585,7 @@ TEST_CASE("Test Dependent Property", "[YamlConfigurationDependentProperty]") { const auto component = std::make_shared<DummyComponent>(); component->setSupportedProperties(std::array<core::PropertyReference, 2>{ core::PropertyDefinitionBuilder<>::createProperty("Prop A").withDescription("Prop A desc").withDefaultValue("val A").isRequired(true).build(), - core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Prop B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true).withDependentProperties({ "Prop A" }).build() + core::PropertyDefinitionBuilder<0, 1>::createProperty("Prop B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true).withDependentProperties({ "Prop A" }).build() }); yamlConfig.validateComponentProperties(*component, "component A", "section A"); REQUIRE(true); // Expected to get here w/o any exceptions @@ -598,7 +598,7 @@ TEST_CASE("Test Dependent Property 2", "[YamlConfigurationDependentProperty2]") const auto component = std::make_shared<DummyComponent>(); component->setSupportedProperties(std::array<core::PropertyReference, 2>{ core::PropertyDefinitionBuilder<>::createProperty("Prop A").withDescription("Prop A desc").isRequired(false).build(), - core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Prop B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true).withDependentProperties({ "Prop A" }).build() + core::PropertyDefinitionBuilder<0, 1>::createProperty("Prop B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true).withDependentProperties({ "Prop A" }).build() }); bool config_failed = false; try { @@ -619,7 +619,7 @@ TEST_CASE("Test Exclusive Property", "[YamlConfigurationExclusiveOfProperty]") { const auto component = std::make_shared<DummyComponent>(); component->setSupportedProperties(std::array<core::PropertyReference, 2>{ core::PropertyDefinitionBuilder<>::createProperty("Prop A").withDescription("Prop A desc").withDefaultValue("val A").isRequired(true).build(), - core::PropertyDefinitionBuilder<0, 0, 0, 1>::createProperty("Prop B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true) + core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Prop B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true) .withExclusiveOfProperties({{ { "Prop A", "^abcd.*$" } }}).build() }); yamlConfig.validateComponentProperties(*component, "component A", "section A"); @@ -633,7 +633,7 @@ TEST_CASE("Test Exclusive Property 2", "[YamlConfigurationExclusiveOfProperty2]" const auto component = std::make_shared<DummyComponent>(); component->setSupportedProperties(std::array<core::PropertyReference, 2>{ core::PropertyDefinitionBuilder<>::createProperty("Prop A").withDescription("Prop A desc").withDefaultValue("val A").isRequired(true).build(), - core::PropertyDefinitionBuilder<0, 0, 0, 1>::createProperty("Prop B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true) + core::PropertyDefinitionBuilder<0, 0, 1>::createProperty("Prop B").withDescription("Prop B desc").withDefaultValue("val B").isRequired(true) .withExclusiveOfProperties({{ { "Prop A", "^val.*$" } }}).build() }); bool config_failed = false; diff --git a/libminifi/include/core/OutputAttributeDefinition.h b/libminifi/include/core/OutputAttributeDefinition.h index 1057c72db..9e4ea9c67 100644 --- a/libminifi/include/core/OutputAttributeDefinition.h +++ b/libminifi/include/core/OutputAttributeDefinition.h @@ -17,9 +17,9 @@ #pragma once #include <array> +#include <span> #include <string_view> -#include "utils/gsl.h" #include "RelationshipDefinition.h" namespace org::apache::nifi::minifi::core { @@ -48,7 +48,7 @@ struct OutputAttributeReference { } std::string_view name; - gsl::span<const RelationshipDefinition> relationships; + std::span<const RelationshipDefinition> relationships; std::string_view description; }; diff --git a/libminifi/include/core/PropertyDefinition.h b/libminifi/include/core/PropertyDefinition.h index 99022855d..1af98de75 100644 --- a/libminifi/include/core/PropertyDefinition.h +++ b/libminifi/include/core/PropertyDefinition.h @@ -18,22 +18,24 @@ #include <array> #include <optional> +#include <span> #include <string_view> #include <utility> +#include "core/Core.h" #include "core/PropertyType.h" #include "utils/gsl.h" namespace org::apache::nifi::minifi::core { -template<size_t NumAllowedValues = 0, size_t NumAllowedTypes = 0, size_t NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0> +template<size_t NumAllowedValues = 0, size_t NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0> struct PropertyDefinition { std::string_view name; std::string_view display_name; std::string_view description; bool is_required = false; std::array<std::string_view, NumAllowedValues> allowed_values; - std::array<std::string_view, NumAllowedTypes> allowed_types; + std::span<const std::string_view> allowed_types; std::array<std::string_view, NumDependentProperties> dependent_properties; std::array<std::pair<std::string_view, std::string_view>, NumExclusiveOfProperties> exclusive_of_properties; std::optional<std::string_view> default_value; @@ -46,18 +48,18 @@ struct PropertyReference { std::string_view display_name; std::string_view description; bool is_required = false; - gsl::span<const std::string_view> allowed_values; - gsl::span<const std::string_view> allowed_types; - gsl::span<const std::string_view> dependent_properties; - gsl::span<const std::pair<std::string_view, std::string_view>> exclusive_of_properties; + std::span<const std::string_view> allowed_values; + std::span<const std::string_view> allowed_types; + std::span<const std::string_view> dependent_properties; + std::span<const std::pair<std::string_view, std::string_view>> exclusive_of_properties; std::optional<std::string_view> default_value; gsl::not_null<const PropertyType*> type = gsl::make_not_null(&StandardPropertyTypes::VALID_TYPE); bool supports_expression_language = false; constexpr PropertyReference() = default; - template<size_t NumAllowedValues = 0, size_t NumAllowedTypes = 0, size_t NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0> - constexpr PropertyReference(const PropertyDefinition<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties>& property_definition) // NOLINT: non-explicit on purpose + template<size_t NumAllowedValues = 0, size_t NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0> + constexpr PropertyReference(const PropertyDefinition<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties>& property_definition) // NOLINT: non-explicit on purpose : name{property_definition.name}, display_name{property_definition.display_name}, description{property_definition.description}, diff --git a/libminifi/include/core/PropertyDefinitionBuilder.h b/libminifi/include/core/PropertyDefinitionBuilder.h index 801faf59e..4ec16838a 100644 --- a/libminifi/include/core/PropertyDefinitionBuilder.h +++ b/libminifi/include/core/PropertyDefinitionBuilder.h @@ -23,75 +23,80 @@ namespace org::apache::nifi::minifi::core { -template <size_t NumAllowedValues = 0, size_t NumAllowedTypes = 0, size_t NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0> +namespace detail { +template<typename... Types> +inline constexpr auto TypeNames = std::array<std::string_view, sizeof...(Types)>{core::className<Types>()...}; +} + +template<size_t NumAllowedValues = 0, size_t NumDependentProperties = 0, size_t NumExclusiveOfProperties = 0> struct PropertyDefinitionBuilder { - static constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> createProperty(std::string_view name) { - PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> builder; + static constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> createProperty(std::string_view name) { + PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> builder; builder.property.name = name; return builder; } - static constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> createProperty(std::string_view name, std::string_view display_name) { - PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> builder; + static constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> createProperty(std::string_view name, std::string_view display_name) { + PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> builder; builder.property.name = name; builder.property.display_name = display_name; return builder; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> withDescription(std::string_view description) { + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> withDescription(std::string_view description) { property.description = description; return *this; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> isRequired(bool required) { + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> isRequired(bool required) { property.is_required = required; return *this; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> supportsExpressionLanguage(bool supports_expression_language) { + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> supportsExpressionLanguage(bool supports_expression_language) { property.supports_expression_language = supports_expression_language; return *this; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> withDefaultValue(std::string_view default_value) { + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> withDefaultValue(std::string_view default_value) { property.default_value = std::optional<std::string_view>{default_value}; // workaround for gcc 11.1; on gcc 11.3 and later, `property.default_value = default_value` works, too return *this; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> withAllowedValues( + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> withAllowedValues( std::array<std::string_view, NumAllowedValues> allowed_values) { property.allowed_values = allowed_values; return *this; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> withAllowedTypes( - std::array<std::string_view, NumAllowedTypes> types) { - property.allowed_types = types; + template<typename... AllowedTypes> + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> withAllowedTypes() { + property.allowed_types = {detail::TypeNames<AllowedTypes...>}; return *this; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> withDependentProperties( + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> withDependentProperties( std::array<std::string_view, NumDependentProperties> dependent_properties) { property.dependent_properties = dependent_properties; return *this; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> withExclusiveOfProperties( + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> withExclusiveOfProperties( std::array<std::pair<std::string_view, std::string_view>, NumExclusiveOfProperties> exclusive_of_properties) { property.exclusive_of_properties = exclusive_of_properties; return *this; } - constexpr PropertyDefinitionBuilder<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> withPropertyType(const PropertyType& property_type) { + constexpr PropertyDefinitionBuilder<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> withPropertyType(const PropertyType& property_type) { property.type = gsl::make_not_null(&property_type); return *this; } - constexpr PropertyDefinition<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> build() { + constexpr PropertyDefinition<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> build() { return property; } - PropertyDefinition<NumAllowedValues, NumAllowedTypes, NumDependentProperties, NumExclusiveOfProperties> property{}; + PropertyDefinition<NumAllowedValues, NumDependentProperties, NumExclusiveOfProperties> property{}; }; } // namespace org::apache::nifi::minifi::core diff --git a/libminifi/src/core/Property.cpp b/libminifi/src/core/Property.cpp index 017deaffb..79f5fc488 100644 --- a/libminifi/src/core/Property.cpp +++ b/libminifi/src/core/Property.cpp @@ -91,18 +91,18 @@ std::vector<std::pair<std::string, std::string>> Property::getExclusiveOfPropert } namespace { -std::vector<PropertyValue> createPropertyValues(gsl::span<const std::string_view> values, const core::PropertyParser& property_parser) { +std::vector<PropertyValue> createPropertyValues(std::span<const std::string_view> values, const core::PropertyParser& property_parser) { return ranges::views::transform(values, [&property_parser](const auto& value) { return property_parser.parse(value); }) | ranges::to<std::vector>; } -inline std::vector<std::string> createStrings(gsl::span<const std::string_view> string_views) { +inline std::vector<std::string> createStrings(std::span<const std::string_view> string_views) { return ranges::views::transform(string_views, [](const auto& string_view) { return std::string{string_view}; }) | ranges::to<std::vector>; } -inline std::vector<std::pair<std::string, std::string>> createStrings(gsl::span<const std::pair<std::string_view, std::string_view>> pairs_of_string_views) { +inline std::vector<std::pair<std::string, std::string>> createStrings(std::span<const std::pair<std::string_view, std::string_view>> pairs_of_string_views) { return ranges::views::transform(pairs_of_string_views, [](const auto& pair_of_string_views) { return std::pair<std::string, std::string>(pair_of_string_views); }) | ranges::to<std::vector>; } diff --git a/libminifi/test/unit/ComponentManifestTests.cpp b/libminifi/test/unit/ComponentManifestTests.cpp index 4f5c24737..907300750 100644 --- a/libminifi/test/unit/ComponentManifestTests.cpp +++ b/libminifi/test/unit/ComponentManifestTests.cpp @@ -61,10 +61,10 @@ class ExampleProcessor : public core::Processor { using Processor::Processor; static constexpr const char* Description = "An example processor"; - static constexpr auto ExampleProperty = core::PropertyDefinitionBuilder<0, 1>::createProperty("Example Property") + static constexpr auto ExampleProperty = core::PropertyDefinitionBuilder<>::createProperty("Example Property") .withDescription("An example property") .isRequired(false) - .withAllowedTypes({core::className<ExampleService>()}) + .withAllowedTypes<ExampleService>() .build(); static constexpr auto Properties = std::array<core::PropertyReference, 1>{ExampleProperty}; static constexpr auto Relationships = std::array<core::RelationshipDefinition, 0>{}; diff --git a/libminifi/test/unit/TypeListTests.cpp b/libminifi/test/unit/TypeListTests.cpp new file mode 100644 index 000000000..463a7a26c --- /dev/null +++ b/libminifi/test/unit/TypeListTests.cpp @@ -0,0 +1,61 @@ +/** + * 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 "../Catch.h" +#include "core/Core.h" +#include "utils/meta/type_list.h" + +class A {}; + +namespace outer { +class B {}; +class C {}; + +namespace inner { +class C {}; +class D {}; +} +} + +template<typename... Types> +using type_list = org::apache::nifi::minifi::utils::meta::type_list<Types...>; + +TEST_CASE("an empty type_list doesn't contain anything") { + STATIC_CHECK_FALSE(type_list<>::contains<A>()); + STATIC_CHECK_FALSE(type_list<>::contains<outer::B>()); + STATIC_CHECK_FALSE(type_list<>::contains<outer::inner::D>()); + STATIC_CHECK_FALSE(type_list<>::contains<std::string>()); +} + +TEST_CASE("a non-empty type_list contains what it should") { + STATIC_CHECK(type_list<A, outer::B>::contains<A>()); + STATIC_CHECK(type_list<A, outer::B>::contains<outer::B>()); + STATIC_CHECK_FALSE(type_list<A, outer::B>::contains<outer::C>()); + STATIC_CHECK_FALSE(type_list<A, outer::B>::contains<outer::inner::D>()); + + STATIC_CHECK(type_list<int, A, std::string>::contains<int>()); + STATIC_CHECK(type_list<int, A, std::string>::contains<A>()); + STATIC_CHECK(type_list<int, A, std::string>::contains<std::string>()); + STATIC_CHECK_FALSE(type_list<int, A, std::string>::contains<double>()); + STATIC_CHECK_FALSE(type_list<int, A, std::string>::contains<outer::C>()); + + namespace inner = outer::inner; + STATIC_CHECK(type_list<outer::C>::contains<outer::C>()); + STATIC_CHECK(type_list<inner::C>::contains<inner::C>()); + STATIC_CHECK_FALSE(type_list<outer::C>::contains<inner::C>()); + STATIC_CHECK_FALSE(type_list<inner::C>::contains<outer::C>()); +}