oscerd opened a new pull request, #29077: URL: https://github.com/apache/camel/pull/29077
Fixes [CAMEL-26235](https://issues.apache.org/jira/browse/CAMEL-26235), found while adding the catalog body types (CAMEL-24961). ## 1. No operation: NullPointerException instead of a clear error **Was:** Without the `CamelHazelcastOperationType` header and without the `defaultOperation` option, the producers of `hazelcast-map`, `hazelcast-multimap`, `hazelcast-replicatedmap`, `hazelcast-list`, `hazelcast-set`, `hazelcast-ringbuffer` and `hazelcast-pncounter` switched on a null operation and failed with a `NullPointerException` ("operation" is null). **Now:** `HazelcastDefaultProducer.lookupOperation`, which every one of them uses, fails with an `IllegalArgumentException`: "No operation to perform: set the CamelHazelcastOperationType header or the defaultOperation option of the endpoint". `hazelcast-queue` and `hazelcast-topic` default to `add` and `publish` and are not affected. ## 2. map consumer: TTL expiry gives no event **Was:** `MapEntryListener` extended the added, updated, removed, evicted, merged and cleared listeners of Hazelcast but not `EntryExpiredListener`, and Hazelcast sends an expiry only to that listener, so an entry whose time to live ended never reached the route. **Now:** `MapEntryListener` also extends `EntryExpiredListener`, and `CamelMapListener.entryExpired` sends an `expired` event as the multimap and replicated map listener does: the `CamelHazelcastListenerAction` header is `expired`, the key is in `CamelHazelcastObjectId`, and there is no body, as for `evicted`. ## 3. list: get without CamelHazelcastObjectIndex fails with a NullPointerException **Was:** `get` unboxed the null index of a message without the `CamelHazelcastObjectIndex` header. **Now:** It fails with an `IllegalArgumentException`: "The get operation needs the index of the item in the CamelHazelcastObjectIndex header". ## 4. list and set: getAll puts the live proxy in the body **Was:** `getAll` set the distributed `IList` or `ISet` proxy itself as the body, so later steps read the live collection and changed the distributed one when they changed the body. **Now:** `getAll` sets a copy: an `ArrayList` for the list and a `LinkedHashSet` for the set, which keeps the order in which the set returned its items. ## 5. queue: removeIf always fails, drainTo without its header passes null **Was:** `removeIf` called `IQueue.removeIf`, which removes through the iterator, and the iterator of a Hazelcast queue does not support remove: the operation always failed with an `UnsupportedOperationException` ("remove() is not supported!"). `drainTo` cast the `CamelHazelcastDrainToCollection` header and passed it as is, so without it the queue failed with a `NullPointerException`, and with a value that is not a `Collection` the cast failed. **Now:** `removeIf` tests the items the queue holds with the `java.util.function.Predicate` of the body and removes the matching ones with one `removeAll` call; the body is `true` when it removed an item. Without a `Predicate` body it fails with an `IllegalArgumentException`. `drainTo` without a `Collection` in the header fails with an `IllegalArgumentException` that names the header, before the queue is touched. ## 6. pncounter: getAndAdd with no body fails with a NullPointerException **Was:** `getAndAdd` unboxed `getBody(Long.class)` into a `long`. **Now:** Without a body that converts to a number it fails with an `IllegalArgumentException`: "The getAndAdd operation needs a numeric body: the number to add to the counter". ## 7. seda: a body that is neither Serializable nor convertible to bytes gives an unclear error **Was:** A body that is not `Serializable` was converted to bytes, and when that gave null the queue failed with "Null item is not allowed!". No body ended the same way. **Now:** The producer fails with an `IllegalArgumentException` before it adds anything: "The body must be Serializable or convertible to bytes to be put on the Hazelcast queue, but it is a <class name>" (the class, never the value), or "The message has no body to put on the Hazelcast queue". ## 8. Docs: replicatedmap intro and old header name in the samples **Was:** The replicated map page started with the intro of the instance component, and the XML and YAML samples of the replicated map, multimap, PN counter and ringbuffer pages set the old `hazelcast.operation.type` header. **Now:** The replicated map page has its own intro, and the samples set `CamelHazelcastOperationType` (the YAML samples in the `expression: constant: expression:` form). `CamelHazelcastOperationType` is now also declared for `hazelcast-pncounter`, whose producer reads it, so its page lists the header the samples set. ## Tests - `HazelcastProducerChecksTest` (new) runs against an embedded Hazelcast member: no operation on each of the seven producers (item 1), list `get` without the index (3), list and set `getAll` give a copy that does not follow the distributed collection and does not change it (4), `removeIf` on a real queue removes the matching items, duplicates included, and gives `false` when nothing matches, `removeIf` without a `Predicate`, `drainTo` without the header leaves the item in the queue (5), `getAndAdd` without a body leaves the counter at 0 (6), and a `hazelcast-seda` body that is not `Serializable` or no body adds nothing to the queue (7). - `HazelcastMapConsumerExpiredTest` (new) puts an entry with a time to live of one second on an embedded member and expects the `added` and then the `expired` event (2). - `HazelcastQueueProducerTest.removeIf` (mock) now expects the iteration and the `removeAll` of the matching items instead of `IQueue.removeIf`. Revert check: with the src/main changes reverted, 18 of the 18 new or changed tests fail, each for the old behaviour: the seven no operation cases, the list `get`, the PN counter `getAndAdd`, the two seda cases, and `drainTo` and `removeIf` without their input (13 tests) fail with the old `NullPointerException` instead of the `IllegalArgumentException`, `removeIf` on a real queue fails with "remove() is not supported!", the `getAll` body is the distributed list or set, the expiring entry gives no event at all, and the mock queue is never iterated. The 15 that pass are the unchanged tests of `HazelcastQueueProducerTest`. camel-hazelcast: 273 tests, 0 failures, 0 errors. ## Docs and generated files - `@BodyTypes`: the map consumer gives no body for `expired`; list and set `getAll` give a copy; the queue producer takes a `Predicate` for `removeIf`, gives a `Boolean` for it, and `drainTo` needs its header. - Map page: the consumer lists the five events and the right header name, and the samples compare with `evicted` (they said `envicted`, which never matched). List, set, queue and PN counter pages: `get` needs the index, `getAll` gives a copy, how `removeIf` and `drainTo` work, and `getAndAdd` needs a numeric body. - Regenerated `hazelcast-map.json`, `hazelcast-list.json`, `hazelcast-set.json`, `hazelcast-queue.json` and `hazelcast-pncounter.json`, and the catalog copies of these and of the eight changed pages. The new header of `hazelcast-pncounter` adds a header name builder to the endpoint DSL. - Upgrade guide entry for 4.24: `getAll` gives a copy, the map consumer routes `expired`, `removeIf` works, and the missing inputs fail with an `IllegalArgumentException`. ## Not changed - `removeIf` is not atomic: the queue offers no conditional remove, so the producer reads the items and then removes the matching ones; an item polled in between is simply not removed. Deprecating the operation was the alternative, but it works this way and the page says it is not atomic. - The `set` operation of the list keeps its message ("Empty position for set operation.") and the generic `IllegalArgumentException` of an unknown operation is unchanged. - The consumer section of the replicated map page still shows a multimap sample and says the update listener is missing, which it is not. Item 8 covers the intro and the samples' header name, so this is left for a follow-up. - With `transferExchange=true` the `hazelcast-seda` producer still drops a body that cannot be serialized (with a WARN), as `DefaultExchangeHolder` does; only the body-only path fails now. Main only, as the other fixes of the CAMEL-24961 follow-ups. _Claude Code on behalf of Andrea Cosentino (oscerd)_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
