Andrea Cosentino created CAMEL-26896:
----------------------------------------

             Summary: camel-openfga - preserve relationship condition on tuple 
write and read
                 Key: CAMEL-26896
                 URL: https://issues.apache.org/jira/browse/CAMEL-26896
             Project: Camel
          Issue Type: Improvement
            Reporter: Andrea Cosentino
            Assignee: Andrea Cosentino
             Fix For: 4.24.0


h3. Background

{{camel-openfga}} lets a Camel route manage relationship tuples in an OpenFGA 
store through {{OpenFgaProducer}}. A relationship tuple has a {{user}}, a 
{{relation}} and an {{object}}. The OpenFGA SDK type {{ClientTupleKey}} can 
additionally carry a *relationship condition*: a condition name plus an 
optional context that OpenFGA evaluates to decide when the relationship holds. 
The SDK models this by having {{ClientTupleKey}} extend 
{{ClientTupleKeyWithoutCondition}}, with {{getCondition()}} present only on the 
{{ClientTupleKey}} subtype. On the read side the server returns the condition 
on {{dev.openfga.sdk.api.model.TupleKey}} via {{getCondition()}}.

h3. Current behaviour

On the write path {{OpenFgaProducer}} funnels every input through a private 
three-field holder {{Tuple}} that keeps only {{user}}, {{relation}} and 
{{object}}:

* {{toTuple(Object)}} matches the input against the 
{{ClientTupleKeyWithoutCondition}} supertype, so a {{ClientTupleKey}} that 
carries a condition still matches, and only {{getUser()}}, {{getRelation()}} 
and {{getObject()}} are read. The condition is never looked at.
* The {{Map}} branch of {{toTuple}} reads only the {{user}}, {{relation}} and 
{{object}} keys. A {{condition}} key on the map is ignored.
* {{writeTuples}} then rebuilds a new {{ClientTupleKey}} from the three 
surviving fields ({{new ClientTupleKey().user(..).relation(..)._object(..)}}), 
with no {{.condition(..)}} call.

The result is that when a route passes {{writeTuples}} a tuple that includes a 
relationship condition, the component writes an unconditioned tuple instead, 
and the caller gets no error and no sign that the condition was not applied.

The read path drops the same information. {{readTuples}} projects each tuple 
into a {{Map}} of {{user}}, {{relation}}, {{object}} and {{timestamp}}. 
{{readChanges}} projects each change into a {{Map}} of {{user}}, {{relation}}, 
{{object}}, {{operation}} and {{timestamp}}. Neither includes the condition 
that the server returned on the {{TupleKey}}, so a route cannot read it back or 
round-trip it.

For reference, {{deleteTuples}} intentionally uses 
{{ClientTupleKeyWithoutCondition}}, because OpenFGA deletes by identity and a 
condition is not part of a delete key. That path is correct and should stay 
unchanged.

h3. Proposed behaviour

Carry the relationship condition through faithfully on both paths:

* Capture the condition in {{toTuple}} when the input is a {{ClientTupleKey}}, 
and define explicit handling for a {{condition}} key (a map of {{name}} and 
{{context}}) in the {{Map}} branch.
* Extend the internal {{Tuple}} holder with an optional condition, and have 
{{writeTuples}} set {{.condition(..)}} on the outgoing {{ClientTupleKey}} when 
one is present. An unconditioned input still produces an unconditioned write.
* In {{readTuples}} and {{readChanges}}, add a {{condition}} entry to each 
result {{Map}} when the server-returned {{TupleKey}} carries one, projected as 
a map of {{name}} and {{context}} (mirroring how {{operation}} is projected as 
a {{String}} rather than an SDK enum).
* Keep {{deleteTuples}} identity-only, and keep the existing rule that an 
endpoint-configured tuple wins over the message body.

h3. Classes and files

* 
{{components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaProducer.java}}:
 {{toTuple}}, {{writeTuples}}, {{readTuples}}, {{readChanges}} and the private 
{{Tuple}} holder.
* {{components/camel-openfga/src/main/docs/openfga-component.adoc}}: document 
the condition on write and the new {{condition}} key in read and change 
results, then regenerate and commit the catalog doc mirror under 
{{catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/}}.
* {{docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc}}: a 
short note that {{writeTuples}} now honours a relationship condition on a 
{{ClientTupleKey}} or {{Map}} input, and that {{readTuples}} and 
{{readChanges}} now include a {{condition}} key when present.

h3. Tests

A new package-private test class (for example {{OpenFgaTupleConditionTest}}) 
covering:

* {{writeTuples}} preserves a condition on a single {{ClientTupleKey}};
* {{writeTuples}} preserves conditions across a collection of tuples;
* {{writeTuples}} with a {{Map}} {{condition}} key preserves it;
* an unconditioned write stays unconditioned (control);
* {{deleteTuples}} stays identity-only (regression guard);
* {{readTuples}} projects a server-returned condition;
* {{readChanges}} projects a server-returned condition.

Follow the module's existing assertion style (AssertJ is already a test 
dependency here) and do not use {{Thread.sleep}}.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to