You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by cd...@apache.org on 2026/10/08 20:14:45 UTC
(camel) 04/12: CAMEL-25333: Add evaluationType path parameter and isEnabled support
This is an automated email from the ASF dual-hosted git repository.
christophd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 9de1478f20efd888d857ea240a69120235c037bc
Author: Christoph Deppisch <ch...@web.de>
AuthorDate: Wed Oct 7 16:17:08 2026 +0200
CAMEL-25333: Add evaluationType path parameter and isEnabled support
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
.../camel/catalog/docs/openfeature-component.adoc | 44 +++++++++++++++-------
.../camel/catalog/docs/openfeature-language.adoc | 2 +-
.../openfeature/OpenFeatureEndpointConfigurer.java | 6 ---
.../openfeature/OpenFeatureEndpointUriFactory.java | 3 +-
.../camel/component/openfeature/openfeature.json | 16 ++++----
.../src/main/docs/openfeature-component.adoc | 44 +++++++++++++++-------
.../src/main/docs/openfeature-language.adoc | 2 +-
.../openfeature/OpenFeatureComponent.java | 12 +++++-
.../openfeature/OpenFeatureConfiguration.java | 9 +++--
.../openfeature/OpenFeatureConstants.java | 2 +-
.../component/openfeature/OpenFeatureEndpoint.java | 19 ++++++++--
.../openfeature/OpenFeatureLanguageTest.java | 2 +-
.../openfeature/OpenFeatureProducerTest.java | 30 ++++++++++++++-
13 files changed, 133 insertions(+), 58 deletions(-)
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfeature-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfeature-component.adoc
index 46bdfbe4734b..f224658909f0 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfeature-component.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfeature-component.adoc
@@ -39,10 +39,12 @@ for this component:
== URI format
----
-openfeature:domain[?options]
+openfeature:domain[/evaluationType][?options]
----
-Where *domain* is the OpenFeature domain to bind the provider to.
+Where *domain* is the OpenFeature domain to bind the provider to and
+*evaluationType* is an optional path parameter that selects the evaluation
+type (`boolean`, `variant`, or `isEnabled`).
// component-configure options: START
// component-configure options: END
@@ -69,13 +71,26 @@ The component resolves the feature flag provider in this order:
== Evaluation type
-The evaluation type (boolean or string) is determined by the `evaluationType`
-option when set:
+The evaluation type (boolean or string) can be set as a path parameter in
+the endpoint URI or as a query parameter / component property:
-* `evaluationType=boolean` — boolean evaluation (`getBooleanValue`)
-* `evaluationType=variant` — string evaluation (`getStringValue`)
+* `boolean` — boolean evaluation (`getBooleanValue`)
+* `isEnabled` — same as `boolean`, semantically indicates a feature toggle check
+* `variant` — string evaluation (`getStringValue`)
-When `evaluationType` is not set, the type is inferred from `defaultValue`:
+When `evaluationType` appears both as a path parameter and as a query
+parameter or component property, the path parameter takes precedence.
+
+Examples:
+
+----
+openfeature:flags/boolean?flagKey=enrichment-enabled
+openfeature:flags/isEnabled?flagKey=enrichment-enabled
+openfeature:flags/variant?flagKey=checkout-banner
+openfeature:flags?flagKey=enrichment-enabled&evaluationType=boolean
+----
+
+When `evaluationType` is not set at all, the type is inferred from `defaultValue`:
* When `defaultValue` is `"true"` or `"false"` (case-insensitive),
boolean evaluation is used.
@@ -172,8 +187,9 @@ Boolean evaluation is the default (`evaluationType` is unset and
=== Variant flag (string evaluation)
-A variant flag returns a string value rather than a boolean. Use
-`evaluationType=variant` to select string evaluation:
+A variant flag returns a string value rather than a boolean. Set
+`evaluationType` to `variant` — either as a path parameter or query
+parameter:
[source,json]
----
@@ -194,7 +210,7 @@ A variant flag returns a string value rather than a boolean. Use
[source,java]
----
from("direct:start")
- .to("openfeature:flags?flagKey=checkout-banner&evaluationType=variant&resultProperty=banner")
+ .to("openfeature:flags/variant?flagKey=checkout-banner&resultProperty=banner")
.log("Banner: ${exchangeProperty.banner}");
----
@@ -236,7 +252,7 @@ to the same variant:
----
from("direct:start")
.setHeader("CamelOpenFeatureTargetingKey", simple("${header.orderId}"))
- .to("openfeature:flags?flagKey=routing-algorithm&evaluationType=variant&resultProperty=algorithm")
+ .to("openfeature:flags/variant?flagKey=routing-algorithm&resultProperty=algorithm")
.toD("direct:route-${exchangeProperty.algorithm}");
----
@@ -274,7 +290,7 @@ The route stores the result in an exchange property and routes dynamically:
[source,java]
----
from("direct:start")
- .to("openfeature:flags?flagKey=order-compliance-v2&evaluationType=variant&resultProperty=orderVariant")
+ .to("openfeature:flags/variant?flagKey=order-compliance-v2&resultProperty=orderVariant")
.toD("direct:orders-${exchangeProperty.orderVariant}");
----
@@ -287,7 +303,7 @@ from("direct:start")
.setHeader("CamelOpenFeatureTargetingKey", constant("order-123"))
.setHeader("CamelOpenFeatureEvaluationContext",
constant(Map.of("customer_tier", "ENTERPRISE")))
- .to("openfeature:flags?flagKey=order-compliance-v2&evaluationType=variant&resultProperty=orderVariant")
+ .to("openfeature:flags/variant?flagKey=order-compliance-v2&resultProperty=orderVariant")
.toD("direct:orders-${exchangeProperty.orderVariant}");
----
@@ -297,7 +313,7 @@ evaluation context:
[source,java]
----
from("direct:start")
- .to("openfeature:flags?flagKey=order-compliance-v2&evaluationType=variant"
+ .to("openfeature:flags/variant?flagKey=order-compliance-v2"
+ "&resultProperty=orderVariant&contextFromBody=true")
.toD("direct:orders-${exchangeProperty.orderVariant}");
----
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfeature-language.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfeature-language.adoc
index 61fba4be34a0..71a09874d522 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfeature-language.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfeature-language.adoc
@@ -120,7 +120,7 @@ properties:
| 0 | `String` | Endpoint URI (default: `openfeature:flags`)
| 1 | `String` | Targeting key
| 2 | `Map<String, Object>` | Evaluation context key-value pairs
-| 3 | `String` | Evaluation type: `boolean` or `variant` (default: `boolean` for createPredicate, `variant` for createExpression)
+| 3 | `String` | Evaluation type: `boolean`, `isEnabled`, or `variant` (default: `boolean` for createPredicate, `variant` for createExpression)
|===
`createPredicate` defaults to boolean evaluation and returns a `Predicate`:
diff --git a/components/camel-openfeature/src/generated/java/org/apache/camel/component/openfeature/OpenFeatureEndpointConfigurer.java b/components/camel-openfeature/src/generated/java/org/apache/camel/component/openfeature/OpenFeatureEndpointConfigurer.java
index 772592acfc52..a0d850f363f7 100644
--- a/components/camel-openfeature/src/generated/java/org/apache/camel/component/openfeature/OpenFeatureEndpointConfigurer.java
+++ b/components/camel-openfeature/src/generated/java/org/apache/camel/component/openfeature/OpenFeatureEndpointConfigurer.java
@@ -30,8 +30,6 @@ public class OpenFeatureEndpointConfigurer extends PropertyConfigurerSupport imp
case "deadline": target.getConfiguration().setDeadline(property(camelContext, int.class, value)); return true;
case "defaultvalue":
case "defaultValue": target.getConfiguration().setDefaultValue(property(camelContext, java.lang.String.class, value)); return true;
- case "evaluationtype":
- case "evaluationType": target.getConfiguration().setEvaluationType(property(camelContext, java.lang.String.class, value)); return true;
case "flagkey":
case "flagKey": target.getConfiguration().setFlagKey(property(camelContext, java.lang.String.class, value)); return true;
case "flags": target.getConfiguration().setFlags(property(camelContext, java.lang.String.class, value)); return true;
@@ -59,8 +57,6 @@ public class OpenFeatureEndpointConfigurer extends PropertyConfigurerSupport imp
case "deadline": return int.class;
case "defaultvalue":
case "defaultValue": return java.lang.String.class;
- case "evaluationtype":
- case "evaluationType": return java.lang.String.class;
case "flagkey":
case "flagKey": return java.lang.String.class;
case "flags": return java.lang.String.class;
@@ -89,8 +85,6 @@ public class OpenFeatureEndpointConfigurer extends PropertyConfigurerSupport imp
case "deadline": return target.getConfiguration().getDeadline();
case "defaultvalue":
case "defaultValue": return target.getConfiguration().getDefaultValue();
- case "evaluationtype":
- case "evaluationType": return target.getConfiguration().getEvaluationType();
case "flagkey":
case "flagKey": return target.getConfiguration().getFlagKey();
case "flags": return target.getConfiguration().getFlags();
diff --git a/components/camel-openfeature/src/generated/java/org/apache/camel/component/openfeature/OpenFeatureEndpointUriFactory.java b/components/camel-openfeature/src/generated/java/org/apache/camel/component/openfeature/OpenFeatureEndpointUriFactory.java
index 0236dcd2e007..c8896e422b27 100644
--- a/components/camel-openfeature/src/generated/java/org/apache/camel/component/openfeature/OpenFeatureEndpointUriFactory.java
+++ b/components/camel-openfeature/src/generated/java/org/apache/camel/component/openfeature/OpenFeatureEndpointUriFactory.java
@@ -17,7 +17,7 @@ import org.apache.camel.spi.EndpointUriFactory;
@Generated("org.apache.camel.maven.packaging.GenerateEndpointUriFactoryMojo")
public class OpenFeatureEndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory {
- private static final String BASE = ":domain";
+ private static final String BASE = ":domain/evaluationType";
private static final Set<String> PROPERTY_NAMES;
private static final Set<String> SECRET_PROPERTY_NAMES;
@@ -59,6 +59,7 @@ public class OpenFeatureEndpointUriFactory extends org.apache.camel.support.comp
Map<String, Object> copy = copyParameters(properties);
uri = buildPathParameter(syntax, uri, "domain", null, true, copy);
+ uri = buildPathParameter(syntax, uri, "evaluationType", null, false, copy);
uri = buildQueryParameters(uri, copy, encode);
return uri;
}
diff --git a/components/camel-openfeature/src/generated/resources/META-INF/org/apache/camel/component/openfeature/openfeature.json b/components/camel-openfeature/src/generated/resources/META-INF/org/apache/camel/component/openfeature/openfeature.json
index 163924b3bbcf..e5795988c0d6 100644
--- a/components/camel-openfeature/src/generated/resources/META-INF/org/apache/camel/component/openfeature/openfeature.json
+++ b/components/camel-openfeature/src/generated/resources/META-INF/org/apache/camel/component/openfeature/openfeature.json
@@ -14,7 +14,7 @@
"version": "4.23.0-SNAPSHOT",
"scheme": "openfeature",
"extendsScheme": "",
- "syntax": "openfeature:domain",
+ "syntax": "openfeature:domain\/evaluationType",
"async": false,
"api": false,
"consumerOnly": false,
@@ -29,7 +29,7 @@
"contextFromBody": { "index": 2, "kind": "property", "displayName": "Context From Body", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "When true, a Map message body is used as the evaluation context. When false [...]
"deadline": { "index": 3, "kind": "property", "displayName": "Deadline", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Deadline in milliseconds for the remote flagd connection." },
"defaultValue": { "index": 4, "kind": "property", "displayName": "Default Value", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "false", "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Default value when flag evaluation fails. When evaluationType is not set [...]
- "evaluationType": { "index": 5, "kind": "property", "displayName": "Evaluation Type", "group": "common", "label": "common", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "boolean", "variant" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "The evaluation type. When set to 'boolean', boolean evaluatio [...]
+ "evaluationType": { "index": 5, "kind": "property", "displayName": "Evaluation Type", "group": "common", "label": "common", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "boolean", "variant", "isEnabled" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "The evaluation type. 'boolean' and 'isEnabled' u [...]
"flagKey": { "index": 6, "kind": "property", "displayName": "Flag Key", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "The feature flag key to evaluate. Can be overridden per message via the CamelOpenFeatureFlagKey header." },
"flags": { "index": 7, "kind": "property", "displayName": "Flags", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "A JSON object defining feature flags in flagd format (inline). Mutually exclusive with flagsResource." },
"flagsResource": { "index": 8, "kind": "property", "displayName": "Flags Resource", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Camel resource URI pointing to a feature flag definition file in flagd format. Mutually exclusi [...]
@@ -45,18 +45,18 @@
"CamelOpenFeatureFlagKey": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Overrides the configured flag key for this message.", "constantName": "org.apache.camel.component.openfeature.OpenFeatureConstants#FLAG_KEY" },
"CamelOpenFeatureTargetingKey": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Sets the targeting key for the OpenFeature evaluation context.", "constantName": "org.apache.camel.component.openfeature.OpenFeatureConstants#TARGETING_KEY" },
"CamelOpenFeatureEvaluationContext": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "java.util.Map", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "A Map of additional evaluation context key-value pairs.", "constantName": "org.apache.camel.component.openfeature.OpenFeatureConstants#EVALUATION_CONTEXT" },
- "CamelOpenFeatureEvaluationType": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Sets the evaluation type (boolean, variant) for the OpenFeature evaluation.", "constantName": "org.apache.camel.component.openfeature.OpenFeatureConstants#EVALUATION_TYPE" },
+ "CamelOpenFeatureEvaluationType": { "index": 3, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Sets the evaluation type (boolean, variant, isEnabled) for the OpenFeature evaluation.", "constantName": "org.apache.camel.component.openfeature.OpenFeatureConstants#EVALUATION_TYPE" },
"CamelOpenFeatureVariant": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The variant name returned by the provider for this evaluation.", "constantName": "org.apache.camel.component.openfeature.OpenFeatureConstants#EVALUATION_VARIANT" },
"CamelOpenFeatureReason": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The reason string returned by the provider for this evaluation.", "constantName": "org.apache.camel.component.openfeature.OpenFeatureConstants#EVALUATION_REASON" },
"CamelOpenFeatureErrorCode": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The error code when the evaluation failed (e.g. FLAG_NOT_FOUND, TYPE_MISMATCH).", "constantName": "org.apache.camel.component.openfeature.OpenFeatureConstants#EVALUATION_ERROR_CODE" }
},
"properties": {
"domain": { "index": 0, "kind": "path", "displayName": "Domain", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The OpenFeature domain to bind the provider to." },
- "certPath": { "index": 1, "kind": "parameter", "displayName": "Cert Path", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Path to the TLS certificate for the remote flagd connection." },
- "contextFromBody": { "index": 2, "kind": "parameter", "displayName": "Context From Body", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "When true, a Map message body is used as the evaluation context. When fals [...]
- "deadline": { "index": 3, "kind": "parameter", "displayName": "Deadline", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Deadline in milliseconds for the remote flagd connection." },
- "defaultValue": { "index": 4, "kind": "parameter", "displayName": "Default Value", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "false", "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Default value when flag evaluation fails. When evaluationType is not se [...]
- "evaluationType": { "index": 5, "kind": "parameter", "displayName": "Evaluation Type", "group": "common", "label": "common", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "boolean", "variant" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "The evaluation type. When set to 'boolean', boolean evaluati [...]
+ "evaluationType": { "index": 1, "kind": "path", "displayName": "Evaluation Type", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "boolean", "variant", "isEnabled" ], "deprecated": false, "autowired": false, "secret": false, "description": "The evaluation type. 'boolean' and 'isEnabled' use boolean evaluation (getBooleanValue). 'variant' uses string evaluation (getStringValue). When not set, the type is inferred from defa [...]
+ "certPath": { "index": 2, "kind": "parameter", "displayName": "Cert Path", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Path to the TLS certificate for the remote flagd connection." },
+ "contextFromBody": { "index": 3, "kind": "parameter", "displayName": "Context From Body", "group": "common", "label": "common", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "When true, a Map message body is used as the evaluation context. When fals [...]
+ "deadline": { "index": 4, "kind": "parameter", "displayName": "Deadline", "group": "common", "label": "common", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 500, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Deadline in milliseconds for the remote flagd connection." },
+ "defaultValue": { "index": 5, "kind": "parameter", "displayName": "Default Value", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "false", "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Default value when flag evaluation fails. When evaluationType is not se [...]
"flagKey": { "index": 6, "kind": "parameter", "displayName": "Flag Key", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "The feature flag key to evaluate. Can be overridden per message via the CamelOpenFeatureFlagKey header." },
"flags": { "index": 7, "kind": "parameter", "displayName": "Flags", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "A JSON object defining feature flags in flagd format (inline). Mutually exclusive with flagsResource." },
"flagsResource": { "index": 8, "kind": "parameter", "displayName": "Flags Resource", "group": "common", "label": "common", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfeature.OpenFeatureConfiguration", "configurationField": "configuration", "description": "Camel resource URI pointing to a feature flag definition file in flagd format. Mutually exclus [...]
diff --git a/components/camel-openfeature/src/main/docs/openfeature-component.adoc b/components/camel-openfeature/src/main/docs/openfeature-component.adoc
index 46bdfbe4734b..f224658909f0 100644
--- a/components/camel-openfeature/src/main/docs/openfeature-component.adoc
+++ b/components/camel-openfeature/src/main/docs/openfeature-component.adoc
@@ -39,10 +39,12 @@ for this component:
== URI format
----
-openfeature:domain[?options]
+openfeature:domain[/evaluationType][?options]
----
-Where *domain* is the OpenFeature domain to bind the provider to.
+Where *domain* is the OpenFeature domain to bind the provider to and
+*evaluationType* is an optional path parameter that selects the evaluation
+type (`boolean`, `variant`, or `isEnabled`).
// component-configure options: START
// component-configure options: END
@@ -69,13 +71,26 @@ The component resolves the feature flag provider in this order:
== Evaluation type
-The evaluation type (boolean or string) is determined by the `evaluationType`
-option when set:
+The evaluation type (boolean or string) can be set as a path parameter in
+the endpoint URI or as a query parameter / component property:
-* `evaluationType=boolean` — boolean evaluation (`getBooleanValue`)
-* `evaluationType=variant` — string evaluation (`getStringValue`)
+* `boolean` — boolean evaluation (`getBooleanValue`)
+* `isEnabled` — same as `boolean`, semantically indicates a feature toggle check
+* `variant` — string evaluation (`getStringValue`)
-When `evaluationType` is not set, the type is inferred from `defaultValue`:
+When `evaluationType` appears both as a path parameter and as a query
+parameter or component property, the path parameter takes precedence.
+
+Examples:
+
+----
+openfeature:flags/boolean?flagKey=enrichment-enabled
+openfeature:flags/isEnabled?flagKey=enrichment-enabled
+openfeature:flags/variant?flagKey=checkout-banner
+openfeature:flags?flagKey=enrichment-enabled&evaluationType=boolean
+----
+
+When `evaluationType` is not set at all, the type is inferred from `defaultValue`:
* When `defaultValue` is `"true"` or `"false"` (case-insensitive),
boolean evaluation is used.
@@ -172,8 +187,9 @@ Boolean evaluation is the default (`evaluationType` is unset and
=== Variant flag (string evaluation)
-A variant flag returns a string value rather than a boolean. Use
-`evaluationType=variant` to select string evaluation:
+A variant flag returns a string value rather than a boolean. Set
+`evaluationType` to `variant` — either as a path parameter or query
+parameter:
[source,json]
----
@@ -194,7 +210,7 @@ A variant flag returns a string value rather than a boolean. Use
[source,java]
----
from("direct:start")
- .to("openfeature:flags?flagKey=checkout-banner&evaluationType=variant&resultProperty=banner")
+ .to("openfeature:flags/variant?flagKey=checkout-banner&resultProperty=banner")
.log("Banner: ${exchangeProperty.banner}");
----
@@ -236,7 +252,7 @@ to the same variant:
----
from("direct:start")
.setHeader("CamelOpenFeatureTargetingKey", simple("${header.orderId}"))
- .to("openfeature:flags?flagKey=routing-algorithm&evaluationType=variant&resultProperty=algorithm")
+ .to("openfeature:flags/variant?flagKey=routing-algorithm&resultProperty=algorithm")
.toD("direct:route-${exchangeProperty.algorithm}");
----
@@ -274,7 +290,7 @@ The route stores the result in an exchange property and routes dynamically:
[source,java]
----
from("direct:start")
- .to("openfeature:flags?flagKey=order-compliance-v2&evaluationType=variant&resultProperty=orderVariant")
+ .to("openfeature:flags/variant?flagKey=order-compliance-v2&resultProperty=orderVariant")
.toD("direct:orders-${exchangeProperty.orderVariant}");
----
@@ -287,7 +303,7 @@ from("direct:start")
.setHeader("CamelOpenFeatureTargetingKey", constant("order-123"))
.setHeader("CamelOpenFeatureEvaluationContext",
constant(Map.of("customer_tier", "ENTERPRISE")))
- .to("openfeature:flags?flagKey=order-compliance-v2&evaluationType=variant&resultProperty=orderVariant")
+ .to("openfeature:flags/variant?flagKey=order-compliance-v2&resultProperty=orderVariant")
.toD("direct:orders-${exchangeProperty.orderVariant}");
----
@@ -297,7 +313,7 @@ evaluation context:
[source,java]
----
from("direct:start")
- .to("openfeature:flags?flagKey=order-compliance-v2&evaluationType=variant"
+ .to("openfeature:flags/variant?flagKey=order-compliance-v2"
+ "&resultProperty=orderVariant&contextFromBody=true")
.toD("direct:orders-${exchangeProperty.orderVariant}");
----
diff --git a/components/camel-openfeature/src/main/docs/openfeature-language.adoc b/components/camel-openfeature/src/main/docs/openfeature-language.adoc
index 61fba4be34a0..71a09874d522 100644
--- a/components/camel-openfeature/src/main/docs/openfeature-language.adoc
+++ b/components/camel-openfeature/src/main/docs/openfeature-language.adoc
@@ -120,7 +120,7 @@ properties:
| 0 | `String` | Endpoint URI (default: `openfeature:flags`)
| 1 | `String` | Targeting key
| 2 | `Map<String, Object>` | Evaluation context key-value pairs
-| 3 | `String` | Evaluation type: `boolean` or `variant` (default: `boolean` for createPredicate, `variant` for createExpression)
+| 3 | `String` | Evaluation type: `boolean`, `isEnabled`, or `variant` (default: `boolean` for createPredicate, `variant` for createExpression)
|===
`createPredicate` defaults to boolean evaluation and returns a `Predicate`:
diff --git a/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureComponent.java b/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureComponent.java
index 8b287829322f..65bb25a1455f 100644
--- a/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureComponent.java
+++ b/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureComponent.java
@@ -54,7 +54,17 @@ public class OpenFeatureComponent extends DefaultComponent {
@Override
protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
- OpenFeatureEndpoint endpoint = new OpenFeatureEndpoint(uri, this, remaining, configuration.copy());
+ String domain = remaining;
+ String evaluationType = null;
+ int idx = remaining.indexOf('/');
+ if (idx >= 0) {
+ domain = remaining.substring(0, idx);
+ String pathValue = remaining.substring(idx + 1);
+ if (!pathValue.isBlank()) {
+ evaluationType = pathValue;
+ }
+ }
+ OpenFeatureEndpoint endpoint = new OpenFeatureEndpoint(uri, this, domain, evaluationType, configuration.copy());
setProperties(endpoint, parameters);
return endpoint;
}
diff --git a/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureConfiguration.java b/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureConfiguration.java
index a71e0651fa8f..cb44bc145c1e 100644
--- a/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureConfiguration.java
+++ b/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureConfiguration.java
@@ -32,10 +32,11 @@ public class OpenFeatureConfiguration implements Cloneable {
+ " selects boolean evaluation, any other value selects string evaluation.")
private String defaultValue = "false";
- @UriParam(label = "common", enums = "boolean,variant",
- description = "The evaluation type. When set to 'boolean', boolean evaluation is used (getBooleanValue)."
- + " When set to 'variant', string evaluation is used (getStringValue)."
- + " When not set, the type is inferred from defaultValue.")
+ @UriParam(label = "common", enums = "boolean,variant,isEnabled",
+ description = "The evaluation type. 'boolean' and 'isEnabled' use boolean evaluation (getBooleanValue)."
+ + " 'variant' uses string evaluation (getStringValue)."
+ + " When not set, the type is inferred from defaultValue."
+ + " Can also be set as a path parameter in the endpoint URI, which takes precedence.")
private String evaluationType;
@UriParam(label = "producer",
diff --git a/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureConstants.java b/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureConstants.java
index fb836b014b90..2686a94ad678 100644
--- a/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureConstants.java
+++ b/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureConstants.java
@@ -32,7 +32,7 @@ public final class OpenFeatureConstants {
javaType = "java.util.Map", applicableFor = "openfeature")
public static final String EVALUATION_CONTEXT = "CamelOpenFeatureEvaluationContext";
- @Metadata(description = "Sets the evaluation type (boolean, variant) for the OpenFeature evaluation.",
+ @Metadata(description = "Sets the evaluation type (boolean, variant, isEnabled) for the OpenFeature evaluation.",
javaType = "String", applicableFor = "openfeature")
public static final String EVALUATION_TYPE = "CamelOpenFeatureEvaluationType";
diff --git a/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureEndpoint.java b/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureEndpoint.java
index 67bd82cca458..3abd2c293368 100644
--- a/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureEndpoint.java
+++ b/components/camel-openfeature/src/main/java/org/apache/camel/component/openfeature/OpenFeatureEndpoint.java
@@ -51,7 +51,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Evaluate feature flags using the OpenFeature specification with flagd. */
-@UriEndpoint(firstVersion = "4.23.0", scheme = "openfeature", title = "OpenFeature", syntax = "openfeature:domain",
+@UriEndpoint(firstVersion = "4.23.0", scheme = "openfeature", title = "OpenFeature",
+ syntax = "openfeature:domain/evaluationType",
producerOnly = true, category = { Category.CLOUD }, headersClass = OpenFeatureConstants.class)
public class OpenFeatureEndpoint extends DefaultEndpoint {
@@ -59,9 +60,15 @@ public class OpenFeatureEndpoint extends DefaultEndpoint {
private static final String DEFAULT_PROVIDER_BEAN = "flags";
@UriPath
- @Metadata(required = true)
+ @Metadata(required = true, description = "The OpenFeature domain to bind the provider to.")
private String domain;
+ @UriPath(enums = "boolean,variant,isEnabled",
+ description = "The evaluation type. 'boolean' and 'isEnabled' use boolean evaluation (getBooleanValue)."
+ + " 'variant' uses string evaluation (getStringValue)."
+ + " When not set, the type is inferred from defaultValue.")
+ private String evaluationType;
+
@UriParam
private OpenFeatureConfiguration configuration;
@@ -69,10 +76,11 @@ public class OpenFeatureEndpoint extends DefaultEndpoint {
private volatile File tempFlagFile;
private volatile boolean ownedProvider;
- public OpenFeatureEndpoint(String uri, OpenFeatureComponent component, String domain,
+ public OpenFeatureEndpoint(String uri, OpenFeatureComponent component, String domain, String evaluationType,
OpenFeatureConfiguration configuration) {
super(uri, component);
this.domain = domain;
+ this.evaluationType = evaluationType;
this.configuration = configuration;
}
@@ -283,6 +291,9 @@ public class OpenFeatureEndpoint extends DefaultEndpoint {
if (evalType == null) {
evalType = exchange.getProperty(OpenFeatureConstants.EVALUATION_TYPE, String.class);
}
+ if (evalType == null) {
+ evalType = evaluationType;
+ }
if (evalType == null) {
evalType = configuration.getEvaluationType();
}
@@ -290,7 +301,7 @@ public class OpenFeatureEndpoint extends DefaultEndpoint {
}
private boolean isBooleanEvaluation(String evalType) {
- if ("boolean".equalsIgnoreCase(evalType)) {
+ if ("boolean".equalsIgnoreCase(evalType) || "isEnabled".equalsIgnoreCase(evalType)) {
return true;
}
if ("variant".equalsIgnoreCase(evalType)) {
diff --git a/components/camel-openfeature/src/test/java/org/apache/camel/component/openfeature/OpenFeatureLanguageTest.java b/components/camel-openfeature/src/test/java/org/apache/camel/component/openfeature/OpenFeatureLanguageTest.java
index 01882f76092f..ba1d246b11a2 100644
--- a/components/camel-openfeature/src/test/java/org/apache/camel/component/openfeature/OpenFeatureLanguageTest.java
+++ b/components/camel-openfeature/src/test/java/org/apache/camel/component/openfeature/OpenFeatureLanguageTest.java
@@ -79,7 +79,7 @@ class OpenFeatureLanguageTest extends CamelTestSupport {
.filter().language("openfeature", "enrichment-enabled")
.to("mock:lang-filtered")
.end()
- .to("openfeature:flags?flagKey=hazmat-compliance-v2&evaluationType=variant&resultProperty=variant");
+ .to("openfeature:flags/variant?flagKey=hazmat-compliance-v2&resultProperty=variant");
}
};
}
diff --git a/components/camel-openfeature/src/test/java/org/apache/camel/component/openfeature/OpenFeatureProducerTest.java b/components/camel-openfeature/src/test/java/org/apache/camel/component/openfeature/OpenFeatureProducerTest.java
index d0bbd29582aa..aa2d71d0b745 100644
--- a/components/camel-openfeature/src/test/java/org/apache/camel/component/openfeature/OpenFeatureProducerTest.java
+++ b/components/camel-openfeature/src/test/java/org/apache/camel/component/openfeature/OpenFeatureProducerTest.java
@@ -57,11 +57,15 @@ class OpenFeatureProducerTest extends CamelTestSupport {
+ "&contextFromBody=true");
from("direct:variant-type")
- .to("openfeature:test-variant?flagKey=new-routing-algorithm&evaluationType=variant&flagsResource="
+ .to("openfeature:test-variant/variant?flagKey=new-routing-algorithm&flagsResource="
+ FLAGS_RESOURCE);
from("direct:boolean-type-explicit")
- .to("openfeature:test-bool-type?flagKey=enrichment-enabled&evaluationType=boolean&flagsResource="
+ .to("openfeature:test-bool-type/boolean?flagKey=enrichment-enabled&flagsResource="
+ + FLAGS_RESOURCE);
+
+ from("direct:is-enabled")
+ .to("openfeature:test-is-enabled/isEnabled?flagKey=enrichment-enabled&flagsResource="
+ FLAGS_RESOURCE);
from("direct:targeted-boolean")
@@ -180,6 +184,28 @@ class OpenFeatureProducerTest extends CamelTestSupport {
assertThat(result).isEqualTo(true);
}
+ @Test
+ void testIsEnabledEvaluationType() {
+ Object result = template.requestBody("direct:is-enabled", "ignored");
+ assertThat(result).isInstanceOf(Boolean.class);
+ assertThat(result).isEqualTo(true);
+ }
+
+ @Test
+ void testIsEnabledDisabledFlag() throws Exception {
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:is-enabled-disabled")
+ .to("openfeature:test-is-enabled-off/isEnabled?flagKey=disabled-flag&flagsResource="
+ + FLAGS_RESOURCE);
+ }
+ });
+ Object result = template.requestBody("direct:is-enabled-disabled", "ignored");
+ assertThat(result).isInstanceOf(Boolean.class);
+ assertThat(result).isEqualTo(false);
+ }
+
@Test
void testInlineFlags() throws Exception {
String inlineFlags = """