shashank created CAMEL-25576:
--------------------------------
Summary: camel-box - event-logs/getEnterpriseEvents returns only
the first chunk of the event log (at most 500 events); the events after it are
dropped silently and cannot be requested
Key: CAMEL-25576
URL: https://issues.apache.org/jira/browse/CAMEL-25576
Project: Camel
Issue Type: Bug
Components: camel-box
Reporter: shashank
Assignee: shashank
{{BoxEventLogsManager.getEnterpriseEvents}} (lines 68-96 at main c3829069cb72),
the only method of the {{box:event-logs}} API:
{code:java}
EnterpriseEventsRequest request = new EnterpriseEventsRequest();
request.position(position).after(after).before(before).types(types);
EventLog eventLog = EventLog.getEnterpriseEvents(boxConnection, request);
List<BoxEvent> results = new ArrayList<>();
for (BoxEvent event : eventLog) {
results.add(event);
}
return results;
{code}
An {{EventLog}} of box-java-sdk 4.16.4 is one response of the events endpoint:
{{EnterpriseEventsRequest}} asks for {{limit = 500}} (the constant in its
constructor), and the response has the events of that chunk and
{{getNextStreamPosition()}} for the next one. The manager sends one request and
returns the events of that response. It does not read the next stream position
and does not return it either (the result is a plain {{List<BoxEvent>}}).
So when more than 500 events lie between {{after}} and {{before}}, the caller
gets the first 500 and has no means to ask for the rest: the {{position}}
parameter needs a stream position, which only the dropped {{EventLog}} had.
Nothing is logged. The javadoc of the method says "@return A list of all the
events that met the given criteria", and for {{position}}: "May be null in
which case all events within bounds returned".
h3. Reproduction
New {{BoxEventLogsManagerPagingTest}} (3 tests) in camel-box-component. A real
{{BoxAPIConnection}} gets a {{RequestInterceptor}} that answers the events
request from memory like the service: at most 500 events from the requested
{{stream_position}}, and {{next_stream_position}} (the fake fails the test
after 20 requests). So the SDK parses real responses. On main all 3 fail:
* {{returnsTheEventsOfEveryChunk}} (1200 events): {{all the events within
bounds, not only the first chunk ==> expected: <1200> but was: <500>}}.
* {{startsAtThePositionOfTheCallerAndReadsToTheEnd}} (position 100 of 1200):
1100 events expected, 500 returned.
* {{stopsWhenTheServiceDoesNotMoveThePosition}}: {{expected: <2> but was: <1>}}
(requests; it checks that the new loop ends when a response repeats the
position it was asked for, and that events returned twice are kept once).
h3. Proposed fix
In {{BoxEventLogsManager.getEnterpriseEvents}}: read on from
{{getNextStreamPosition()}} until a chunk is empty, which is the end of the
events within bounds; also stop when the service returns no next position or
the position it was asked for. The events are collected in a {{LinkedHashSet}}
({{BoxResource.equals}} compares the id), so an event that the service returns
in two chunks is kept once and the order of the service is kept. The signature
is unchanged; the javadoc of the return value now says that the log is read
chunk by chunk and kept in memory.
Behaviour change, with a 4.24 upgrade-guide entry: the operation returns all
the events between {{after}} and {{before}}. Cost: one request per chunk of 500
events and one more that finds the end (two requests where main sent one, when
everything fits in one chunk). A wide {{after}} / {{before}} window now returns
every event in one list, with that many requests and more memory; the upgrade
note and the javadoc say to narrow the window for a large event log. The loop
has no limit of its own on the number of chunks: it ends on an empty chunk, on
a missing next position or on a position that did not move. I end the loop on
an empty chunk and not on a chunk shorter than the limit because I could not
confirm from the SDK that a short chunk always means the end. camel-box-api and
camel-box-component unit tests with the fix: 6, 0 failures (the integration
tests need a Box account and were not run; nothing was run against Box).
Found with a Lean 4 model of a position-paged service: the event log is a list,
a response is a {{take}} / {{drop}} slice of it and the position after it.
Property: the result is the log from the position of the caller to its end,
every event once and in order. Counterexample for main: with chunks of two,
{{[1, 2, 3]}} gives {{[1, 2]}} ({{cex_third_event_dropped}}); with a chunk of
500, 501 events give 500 ({{cex_501_events}}). In the model, reading chunk
after chunk returns the list from the start position to its end
({{fix_meets_spec}}), and the same as main when the events fit in one chunk
({{fix_eq_main_one_chunk}}). The model says nothing about the real service.
Then confirmed with the real class as described.
Affected: main (4.23.0-SNAPSHOT at c3829069cb72), and the release branches
camel-4.18.x (c3fd5317a5a0), camel-4.22.x (2821f284056c) and camel-4.23.x
(197e70656a41): lines 66-95 of {{BoxEventLogsManager}} (the javadoc of the
return value and the whole method body) are identical to main on all three.
Read, not run.
Duplicate check (2026-10-12): JIRA text "box getEnterpriseEvents" (none), "box
enterprise events position" (2, unrelated: CAMEL-12998, CAMEL-12297); GitHub
pull requests "box enterprise events": none; no open pull request touches
camel-box.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)