This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 7d361fc3d308 CAMEL-26173: camel-web3j - atBlock, fromBlock and toBlock
default to latest, ETH_GET_TRANSACTION_RECEIPT gives the receipt, and a missing
operation fails with a clear message (#29002)
7d361fc3d308 is described below
commit 7d361fc3d30813a22cad962778c5e79edf2de4e1
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Nov 3 11:39:42 2026 +0100
CAMEL-26173: camel-web3j - atBlock, fromBlock and toBlock default to
latest, ETH_GET_TRANSACTION_RECEIPT gives the receipt, and a missing operation
fails with a clear message (#29002)
…latest, ETH_GET_TRANSACTION_RECEIPT gives the receipt, and a missing
operation fails with a clear message
The atBlock, fromBlock and toBlock options were documented with the default
latest but were null, so ETH_GET_BALANCE, ETH_GET_BLOCK_BY_NUMBER and the
other
operations that take a block failed with a NullPointerException, and so did
the
replay consumers. They are now initialized to latest.
ETH_GET_TRANSACTION_RECEIPT set an Optional as the body; it now sets the
TransactionReceipt, or null, like the ETH_GET_TRANSACTION_BY_* operations.
The default operation transaction is not an operation: the consumer now
fails
to start with a message that lists the observable operations (and accepts
them
in lower case like the producer), and the producer fails the exchange with a
message that asks for the operation option or the CamelWeb3jOperation
header.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../org/apache/camel/catalog/components/web3j.json | 6 +-
.../org/apache/camel/component/web3j/web3j.json | 6 +-
.../camel/component/web3j/Web3jConfiguration.java | 11 +-
.../camel/component/web3j/Web3jConsumer.java | 24 +++-
.../camel/component/web3j/Web3jEndpoint.java | 8 +-
.../camel/component/web3j/Web3jProducer.java | 18 ++-
.../camel/component/web3j/Web3jConsumerTest.java | 126 +++++++++++++++++++++
.../camel/component/web3j/Web3jProducerTest.java | 61 +++++++++-
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 16 +++
.../dsl/Web3jComponentBuilderFactory.java | 8 +-
.../endpoint/dsl/Web3jEndpointBuilderFactory.java | 24 +++-
11 files changed, 284 insertions(+), 24 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/web3j.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/web3j.json
index b0e0b75ce1c8..f2c6e04c0171 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/web3j.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/web3j.json
@@ -30,7 +30,7 @@
"fromBlock": { "index": 3, "kind": "property", "displayName": "From
Block", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "latest", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The block number, or the string latest for the
last mined block or pending, earliest for [...]
"fullTransactionObjects": { "index": 4, "kind": "property", "displayName":
"Full Transaction Objects", "group": "common", "label": "common", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false,
"configurationClass": "org.apache.camel.component.web3j.Web3jConfiguration",
"configurationField": "configuration", "description": "If true it returns the
full transaction objects, if false only the hashes [...]
"gasLimit": { "index": 5, "kind": "property", "displayName": "Gas Limit",
"group": "common", "label": "", "required": false, "type": "object",
"javaType": "java.math.BigInteger", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The maximum gas allowed in this block." },
- "operation": { "index": 6, "kind": "property", "displayName": "Operation",
"group": "common", "label": "common", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "transaction", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "Operation to use." },
+ "operation": { "index": 6, "kind": "property", "displayName": "Operation",
"group": "common", "label": "common", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "transaction", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "Operation to use. The producer needs an
operation, set with this option or the CamelW [...]
"privateFor": { "index": 7, "kind": "property", "displayName": "Private
For", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "A comma separated transaction privateFor nodes
with public keys in a Quorum network" },
"quorumAPI": { "index": 8, "kind": "property", "displayName": "Quorum
API", "group": "common", "label": "common", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "If true, this will support Quorum API." },
"toAddress": { "index": 9, "kind": "property", "displayName": "To
Address", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The address the transaction is directed to." },
@@ -107,7 +107,7 @@
"bodyTypes": {
"consumerOut": { "carriers": [ "text", "pojo", "null" ], "dependsOn": [
"operation" ], "byOption": [ { "option": "operation", "value":
"ETH_BLOCK_HASH_OBSERVABLE", "carriers": [ "text", "null" ], "javaType":
"java.lang.String" }, { "option": "operation", "value":
"ETH_PENDING_TRANSACTION_HASH_OBSERVABLE", "carriers": [ "text", "null" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"BLOCK_OBSERVABLE", "carriers": [ "pojo", "null" ], "javaType":
"org.web3j.protoc [...]
"producerIn": { "carriers": [ "any" ], "description": "The operations take
their input from headers and options, except WEB3_SHA3, DB_PUT_STRING,
DB_PUT_HEX and QUORUM_GET_PRIVATE_PAYLOAD, which send the body converted to a
String: a Map or a POJO is sent as its toString" },
- "producerOut": { "carriers": [ "unchanged" ], "byOption": [ { "option":
"operation", "value": "WEB3_CLIENT_VERSION", "carriers": [ "text" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"WEB3_SHA3", "carriers": [ "text" ], "javaType": "java.lang.String" }, {
"option": "operation", "value": "NET_VERSION", "carriers": [ "text" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"ETH_PROTOCOL_VERSION", "carriers": [ "text" ], "javaType": "java.l [...]
+ "producerOut": { "carriers": [ "unchanged" ], "byOption": [ { "option":
"operation", "value": "WEB3_CLIENT_VERSION", "carriers": [ "text" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"WEB3_SHA3", "carriers": [ "text" ], "javaType": "java.lang.String" }, {
"option": "operation", "value": "NET_VERSION", "carriers": [ "text" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"ETH_PROTOCOL_VERSION", "carriers": [ "text" ], "javaType": "java.l [...]
},
"properties": {
"nodeAddress": { "index": 0, "kind": "path", "displayName": "Node
Address", "group": "common", "label": "", "required": true, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Sets the node address used
to communicate" },
@@ -116,7 +116,7 @@
"fromBlock": { "index": 3, "kind": "parameter", "displayName": "From
Block", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "latest", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The block number, or the string latest for the
last mined block or pending, earliest for [...]
"fullTransactionObjects": { "index": 4, "kind": "parameter",
"displayName": "Full Transaction Objects", "group": "common", "label":
"common", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "If true it returns the full transaction
objects, if false only the hashe [...]
"gasLimit": { "index": 5, "kind": "parameter", "displayName": "Gas Limit",
"group": "common", "label": "", "required": false, "type": "object",
"javaType": "java.math.BigInteger", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The maximum gas allowed in this block." },
- "operation": { "index": 6, "kind": "parameter", "displayName":
"Operation", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "transaction", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "Operation to use." },
+ "operation": { "index": 6, "kind": "parameter", "displayName":
"Operation", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "transaction", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "Operation to use. The producer needs an
operation, set with this option or the Camel [...]
"privateFor": { "index": 7, "kind": "parameter", "displayName": "Private
For", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "A comma separated transaction privateFor nodes
with public keys in a Quorum network" },
"quorumAPI": { "index": 8, "kind": "parameter", "displayName": "Quorum
API", "group": "common", "label": "common", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "If true, this will support Quorum API." },
"toAddress": { "index": 9, "kind": "parameter", "displayName": "To
Address", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The address the transaction is directed to." },
diff --git
a/components/camel-web3j/src/generated/resources/META-INF/org/apache/camel/component/web3j/web3j.json
b/components/camel-web3j/src/generated/resources/META-INF/org/apache/camel/component/web3j/web3j.json
index b0e0b75ce1c8..f2c6e04c0171 100644
---
a/components/camel-web3j/src/generated/resources/META-INF/org/apache/camel/component/web3j/web3j.json
+++
b/components/camel-web3j/src/generated/resources/META-INF/org/apache/camel/component/web3j/web3j.json
@@ -30,7 +30,7 @@
"fromBlock": { "index": 3, "kind": "property", "displayName": "From
Block", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "latest", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The block number, or the string latest for the
last mined block or pending, earliest for [...]
"fullTransactionObjects": { "index": 4, "kind": "property", "displayName":
"Full Transaction Objects", "group": "common", "label": "common", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false,
"configurationClass": "org.apache.camel.component.web3j.Web3jConfiguration",
"configurationField": "configuration", "description": "If true it returns the
full transaction objects, if false only the hashes [...]
"gasLimit": { "index": 5, "kind": "property", "displayName": "Gas Limit",
"group": "common", "label": "", "required": false, "type": "object",
"javaType": "java.math.BigInteger", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The maximum gas allowed in this block." },
- "operation": { "index": 6, "kind": "property", "displayName": "Operation",
"group": "common", "label": "common", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "transaction", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "Operation to use." },
+ "operation": { "index": 6, "kind": "property", "displayName": "Operation",
"group": "common", "label": "common", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "transaction", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "Operation to use. The producer needs an
operation, set with this option or the CamelW [...]
"privateFor": { "index": 7, "kind": "property", "displayName": "Private
For", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "A comma separated transaction privateFor nodes
with public keys in a Quorum network" },
"quorumAPI": { "index": 8, "kind": "property", "displayName": "Quorum
API", "group": "common", "label": "common", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "If true, this will support Quorum API." },
"toAddress": { "index": 9, "kind": "property", "displayName": "To
Address", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The address the transaction is directed to." },
@@ -107,7 +107,7 @@
"bodyTypes": {
"consumerOut": { "carriers": [ "text", "pojo", "null" ], "dependsOn": [
"operation" ], "byOption": [ { "option": "operation", "value":
"ETH_BLOCK_HASH_OBSERVABLE", "carriers": [ "text", "null" ], "javaType":
"java.lang.String" }, { "option": "operation", "value":
"ETH_PENDING_TRANSACTION_HASH_OBSERVABLE", "carriers": [ "text", "null" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"BLOCK_OBSERVABLE", "carriers": [ "pojo", "null" ], "javaType":
"org.web3j.protoc [...]
"producerIn": { "carriers": [ "any" ], "description": "The operations take
their input from headers and options, except WEB3_SHA3, DB_PUT_STRING,
DB_PUT_HEX and QUORUM_GET_PRIVATE_PAYLOAD, which send the body converted to a
String: a Map or a POJO is sent as its toString" },
- "producerOut": { "carriers": [ "unchanged" ], "byOption": [ { "option":
"operation", "value": "WEB3_CLIENT_VERSION", "carriers": [ "text" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"WEB3_SHA3", "carriers": [ "text" ], "javaType": "java.lang.String" }, {
"option": "operation", "value": "NET_VERSION", "carriers": [ "text" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"ETH_PROTOCOL_VERSION", "carriers": [ "text" ], "javaType": "java.l [...]
+ "producerOut": { "carriers": [ "unchanged" ], "byOption": [ { "option":
"operation", "value": "WEB3_CLIENT_VERSION", "carriers": [ "text" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"WEB3_SHA3", "carriers": [ "text" ], "javaType": "java.lang.String" }, {
"option": "operation", "value": "NET_VERSION", "carriers": [ "text" ],
"javaType": "java.lang.String" }, { "option": "operation", "value":
"ETH_PROTOCOL_VERSION", "carriers": [ "text" ], "javaType": "java.l [...]
},
"properties": {
"nodeAddress": { "index": 0, "kind": "path", "displayName": "Node
Address", "group": "common", "label": "", "required": true, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "description": "Sets the node address used
to communicate" },
@@ -116,7 +116,7 @@
"fromBlock": { "index": 3, "kind": "parameter", "displayName": "From
Block", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "latest", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The block number, or the string latest for the
last mined block or pending, earliest for [...]
"fullTransactionObjects": { "index": 4, "kind": "parameter",
"displayName": "Full Transaction Objects", "group": "common", "label":
"common", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "If true it returns the full transaction
objects, if false only the hashe [...]
"gasLimit": { "index": 5, "kind": "parameter", "displayName": "Gas Limit",
"group": "common", "label": "", "required": false, "type": "object",
"javaType": "java.math.BigInteger", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The maximum gas allowed in this block." },
- "operation": { "index": 6, "kind": "parameter", "displayName":
"Operation", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "transaction", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "Operation to use." },
+ "operation": { "index": 6, "kind": "parameter", "displayName":
"Operation", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "transaction", "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "Operation to use. The producer needs an
operation, set with this option or the Camel [...]
"privateFor": { "index": 7, "kind": "parameter", "displayName": "Private
For", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "A comma separated transaction privateFor nodes
with public keys in a Quorum network" },
"quorumAPI": { "index": 8, "kind": "parameter", "displayName": "Quorum
API", "group": "common", "label": "common", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "If true, this will support Quorum API." },
"toAddress": { "index": 9, "kind": "parameter", "displayName": "To
Address", "group": "common", "label": "common", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.web3j.Web3jConfiguration", "configurationField":
"configuration", "description": "The address the transaction is directed to." },
diff --git
a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConfiguration.java
b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConfiguration.java
index 57e56cdf5d82..0b30e2d57b9f 100644
---
a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConfiguration.java
+++
b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConfiguration.java
@@ -31,13 +31,13 @@ public class Web3jConfiguration implements Cloneable {
private String operation = Web3jConstants.TRANSACTION.toLowerCase(); //
TODO: Make this an enum
@UriParam(label = "common", defaultValue = "latest")
- private String fromBlock;
+ private String fromBlock = "latest";
@UriParam(label = "common", defaultValue = "latest")
- private String toBlock;
+ private String toBlock = "latest";
@UriParam(label = "producer", defaultValue = "latest")
- private String atBlock;
+ private String atBlock = "latest";
@UriParam(label = "common")
private String addresses;
@@ -524,7 +524,10 @@ public class Web3jConfiguration implements Cloneable {
}
/**
- * Operation to use.
+ * Operation to use. The producer needs an operation, set with this option
or the CamelWeb3jOperation header. The
+ * consumer needs one of the observable operations: ETH_LOG_OBSERVABLE,
ETH_BLOCK_HASH_OBSERVABLE,
+ * ETH_PENDING_TRANSACTION_HASH_OBSERVABLE, TRANSACTION_OBSERVABLE,
PENDING_TRANSACTION_OBSERVABLE,
+ * BLOCK_OBSERVABLE, REPLAY_BLOCKS_OBSERVABLE or
REPLAY_TRANSACTIONS_OBSERVABLE.
*/
public void setOperation(String operation) {
this.operation = operation;
diff --git
a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConsumer.java
b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConsumer.java
index ebff5d510a80..cd7b7941bfc3 100644
---
a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConsumer.java
+++
b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jConsumer.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.component.web3j;
+import java.util.List;
+import java.util.Locale;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -41,6 +43,11 @@ public class Web3jConsumer extends DefaultConsumer {
private static final Logger LOG =
LoggerFactory.getLogger(Web3jConsumer.class);
// the delay before subscribing again after a subscription ended with an
error
private static final long DEFAULT_RESUBSCRIBE_DELAY = 15000;
+ private static final List<String> OPERATIONS = List.of(
+ Web3jConstants.ETH_LOG_OBSERVABLE,
Web3jConstants.ETH_BLOCK_HASH_OBSERVABLE,
+ Web3jConstants.ETH_PENDING_TRANSACTION_HASH_OBSERVABLE,
Web3jConstants.TRANSACTION_OBSERVABLE,
+ Web3jConstants.PENDING_TRANSACTION_OBSERVABLE,
Web3jConstants.BLOCK_OBSERVABLE,
+ Web3jConstants.REPLAY_BLOCKS_OBSERVABLE,
Web3jConstants.REPLAY_TRANSACTIONS_OBSERVABLE);
private final Web3jConfiguration configuration;
private Web3j web3j;
private volatile Disposable subscription;
@@ -72,6 +79,13 @@ public class Web3jConsumer extends DefaultConsumer {
protected void doStart() throws Exception {
super.doStart();
+ String operation = operation();
+ if (operation == null || !OPERATIONS.contains(operation)) {
+ throw new IllegalArgumentException(
+ "Unsupported operation " + configuration.getOperation()
+ + " for the web3j consumer: set
the operation option to one of "
+ + String.join(", ",
OPERATIONS));
+ }
this.web3j = getEndpoint().getWeb3j();
failing = false;
resubscribeExecutor =
getEndpoint().getCamelContext().getExecutorServiceManager()
@@ -86,7 +100,7 @@ public class Web3jConsumer extends DefaultConsumer {
} else {
LOG.info("Subscribing to: {}", endpoint.getNodeAddress());
}
- switch (configuration.getOperation()) {
+ switch (operation()) {
case Web3jConstants.ETH_LOG_OBSERVABLE:
EthFilter ethFilter =
Web3jEndpoint.buildEthFilter(toDefaultBlockParameter(configuration.getFromBlock()),
toDefaultBlockParameter(configuration.getToBlock()),
configuration.getAddressesAsList(),
@@ -160,6 +174,14 @@ public class Web3jConsumer extends DefaultConsumer {
}
}
+ /**
+ * The operation of the consumer, which may be written in lower case like
the operations of the producer.
+ */
+ private String operation() {
+ String operation = configuration.getOperation();
+ return operation != null ? operation.toUpperCase(Locale.ROOT) : null;
+ }
+
/**
* An item was received, so the subscription works: an error after this
one is routed and logged again.
*/
diff --git
a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jEndpoint.java
b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jEndpoint.java
index 84765eb6e2c0..7e348bcf07c9 100644
---
a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jEndpoint.java
+++
b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jEndpoint.java
@@ -266,16 +266,16 @@ import org.web3j.quorum.Quorum;
carriers = {
Carrier.POJO, Carrier.NULL },
javaType =
"org.web3j.protocol.core.methods.response.Transaction"),
@BodyType.When(option =
"operation", value = "ETH_GET_TRANSACTION_RECEIPT",
- carriers =
Carrier.POJO,
- javaType =
"java.util.Optional<org.web3j.protocol.core.methods.response.TransactionReceipt>"),
+ carriers = {
Carrier.POJO, Carrier.NULL },
+ javaType =
"org.web3j.protocol.core.methods.response.TransactionReceipt"),
@BodyType.When(option =
"operation", value = "QUORUM_NODE_INFO",
carriers =
Carrier.POJO,
javaType =
"org.web3j.protocol.core.methods.response.admin.AdminNodeInfo.NodeInfo") },
description = "The result of the JSON-RPC
call of the operation, selected by the"
+ " CamelWeb3jOperation
header or the operation option: a String for a"
+ " hash, an address or hex
data, a BigInteger for a quantity, a Boolean, a"
- + " List, or a web3j object
such as an EthBlock.Block, a Transaction (null"
- + " when not found) or an
Optional of a TransactionReceipt. On a JSON-RPC"
+ + " List, or a web3j object
such as an EthBlock.Block, a Transaction or a"
+ + " TransactionReceipt (null
when not found). On a JSON-RPC"
+ " error the body is
unchanged and the exchange fails, with the"
+ " CamelWeb3jErrorCode,
CamelWeb3jErrorData and CamelWeb3jErrorMessage headers"))
public class Web3jEndpoint extends DefaultEndpoint implements
EndpointServiceLocation {
diff --git
a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jProducer.java
b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jProducer.java
index d4619fe14a37..c37f0b206bec 100644
---
a/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jProducer.java
+++
b/components/camel-web3j/src/main/java/org/apache/camel/component/web3j/Web3jProducer.java
@@ -97,7 +97,7 @@ public class Web3jProducer extends HeaderSelectorProducer {
private final Web3jConfiguration configuration;
public Web3jProducer(Web3jEndpoint endpoint, final Web3jConfiguration
configuration) {
- super(endpoint, Web3jConstants.OPERATION,
configuration::getOperationOrDefault);
+ super(endpoint, Web3jConstants.OPERATION, () ->
defaultOperation(configuration));
web3j = endpoint.getWeb3j();
this.configuration = configuration;
if (web3j instanceof Quorum) {
@@ -110,6 +110,20 @@ public class Web3jProducer extends HeaderSelectorProducer {
return (Web3jEndpoint) super.getEndpoint();
}
+ /**
+ * The operation of the endpoint, used when the CamelWeb3jOperation header
is not set. The default value of the
+ * operation option, transaction, is not an operation of the producer.
+ */
+ private static String defaultOperation(Web3jConfiguration configuration) {
+ String operation = configuration.getOperationOrDefault();
+ if (Web3jConstants.TRANSACTION.equalsIgnoreCase(operation)) {
+ throw new IllegalArgumentException(
+ "No operation for the web3j producer: set the operation
option or the " + Web3jConstants.OPERATION
+ + " header");
+ }
+ return operation;
+ }
+
@InvokeOnHeader(Web3jConstants.WEB3_CLIENT_VERSION)
void web3ClientVersion(Message message) throws IOException {
Request<?, Web3ClientVersion> web3ClientVersionRequest =
web3j.web3ClientVersion();
@@ -561,7 +575,7 @@ public class Web3jProducer extends HeaderSelectorProducer {
EthGetTransactionReceipt response = request.send();
boolean hasError = checkForError(message, response);
if (!hasError) {
- message.setBody(response.getTransactionReceipt());
+ message.setBody(response.getTransactionReceipt().orElse(null));
}
}
diff --git
a/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jConsumerTest.java
b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jConsumerTest.java
new file mode 100644
index 000000000000..bc5c78723a3f
--- /dev/null
+++
b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jConsumerTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+package org.apache.camel.component.web3j;
+
+import io.reactivex.Flowable;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.web3j.protocol.Web3j;
+import org.web3j.protocol.core.DefaultBlockParameterName;
+import org.web3j.protocol.core.methods.request.EthFilter;
+import org.web3j.protocol.core.methods.response.EthBlock;
+import org.web3j.protocol.core.methods.response.Log;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class Web3jConsumerTest extends CamelTestSupport {
+
+ private final Web3j web3j = mock(Web3j.class);
+
+ @EndpointInject("mock:result")
+ private MockEndpoint result;
+
+ Web3jConsumerTest() {
+ // the mocked client is stubbed before the context starts
+ testConfiguration().withUseAdviceWith(true);
+ }
+
+ @Override
+ protected void bindToRegistry(Registry registry) {
+ registry.bind("mockWeb3j", web3j);
+ }
+
+ private static EthBlock block(String number) {
+ EthBlock.Block block = new EthBlock.Block();
+ block.setNumber(number);
+ EthBlock ethBlock = new EthBlock();
+ ethBlock.setResult(block);
+ return ethBlock;
+ }
+
+ private void startRoute(String options) throws Exception {
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("web3j://http://127.0.0.1:8545?web3j=#mockWeb3j" +
options)
+ .routeId("web3j").autoStartup(false)
+ .to("mock:result");
+ }
+ });
+ context.start();
+ context.getRouteController().startRoute("web3j");
+ }
+
+ @Test
+ void consumerWithoutOperationFailsToStart() {
+ Exception e = assertThrows(Exception.class, () -> startRoute(""));
+ Throwable cause = e;
+ while (!(cause instanceof IllegalArgumentException) &&
cause.getCause() != null) {
+ cause = cause.getCause();
+ }
+ assertTrue(cause.getMessage().startsWith(
+ "Unsupported operation transaction for the web3j consumer: set
the operation option to one of"
+ + " ETH_LOG_OBSERVABLE,
ETH_BLOCK_HASH_OBSERVABLE"),
+ cause.getMessage());
+ }
+
+ @Test
+ void operationInLowerCase() throws Exception {
+
when(web3j.blockFlowable(anyBoolean())).thenReturn(Flowable.concat(Flowable.just(block("0x1")),
Flowable.never()));
+ result.expectedMessageCount(1);
+
+ startRoute("&operation=block_observable");
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ @Test
+ void replayOfBlocksFromAndToTheLatestBlockByDefault() throws Exception {
+
when(web3j.replayPastBlocksFlowable(eq(DefaultBlockParameterName.LATEST),
eq(DefaultBlockParameterName.LATEST),
+ anyBoolean())).thenReturn(Flowable.just(block("0x1")));
+ // the block, then the message that ends the subscription
+ result.expectedMessageCount(2);
+
+ startRoute("&operation=" + Web3jConstants.REPLAY_BLOCKS_OBSERVABLE);
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ @Test
+ void logFilterFromAndToTheLatestBlockByDefault() throws Exception {
+ ArgumentCaptor<EthFilter> filter =
ArgumentCaptor.forClass(EthFilter.class);
+ when(web3j.ethLogFlowable(filter.capture())).thenReturn(Flowable.<Log>
never());
+
+ startRoute("&operation=" + Web3jConstants.ETH_LOG_OBSERVABLE);
+
+ verify(web3j).ethLogFlowable(filter.getValue());
+ assertEquals(DefaultBlockParameterName.LATEST,
filter.getValue().getFromBlock());
+ assertEquals(DefaultBlockParameterName.LATEST,
filter.getValue().getToBlock());
+ }
+}
diff --git
a/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jProducerTest.java
b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jProducerTest.java
index 54b8ff66f588..aae56348d383 100644
---
a/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jProducerTest.java
+++
b/components/camel-web3j/src/test/java/org/apache/camel/component/web3j/Web3jProducerTest.java
@@ -82,15 +82,20 @@ import org.web3j.protocol.core.methods.response.ShhPost;
import org.web3j.protocol.core.methods.response.ShhUninstallFilter;
import org.web3j.protocol.core.methods.response.ShhVersion;
import org.web3j.protocol.core.methods.response.Transaction;
+import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.core.methods.response.Web3ClientVersion;
import org.web3j.protocol.core.methods.response.Web3Sha3;
import static org.apache.camel.component.web3j.Web3jConstants.OPERATION;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
public class Web3jProducerTest extends Web3jMockTestSupport {
@@ -291,6 +296,19 @@ public class Web3jProducerTest extends
Web3jMockTestSupport {
assertEquals(BigInteger.ONE, body);
}
+ @Test
+ public void ethGetBalanceAtTheLatestBlockByDefaultTest() throws Exception {
+ EthGetBalance response = Mockito.mock(EthGetBalance.class);
+ Mockito.when(mockWeb3j.ethGetBalance(any(),
any())).thenReturn(request);
+ Mockito.when(request.send()).thenReturn(response);
+ Mockito.when(response.getBalance()).thenReturn(BigInteger.ONE);
+
+ Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION,
Web3jConstants.ETH_GET_BALANCE);
+ template.send(exchange);
+ assertEquals(BigInteger.ONE,
exchange.getIn().getBody(BigInteger.class));
+ Mockito.verify(mockWeb3j).ethGetBalance(any(),
eq(DefaultBlockParameterName.LATEST));
+ }
+
@Test
public void ethGetStorageAtTest() throws Exception {
EthGetStorageAt response = Mockito.mock(EthGetStorageAt.class);
@@ -463,6 +481,19 @@ public class Web3jProducerTest extends
Web3jMockTestSupport {
assertNotNull(body);
}
+ @Test
+ public void ethGetBlockByNumberAtTheLatestBlockByDefaultTest() throws
Exception {
+ EthBlock response = Mockito.mock(EthBlock.class);
+ Mockito.when(mockWeb3j.ethGetBlockByNumber(any(),
anyBoolean())).thenReturn(request);
+ Mockito.when(request.send()).thenReturn(response);
+
Mockito.when(response.getBlock()).thenReturn(Mockito.mock(EthBlock.Block.class));
+
+ Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION,
Web3jConstants.ETH_GET_BLOCK_BY_NUMBER);
+ template.send(exchange);
+ assertNotNull(exchange.getIn().getBody(EthBlock.Block.class));
+
Mockito.verify(mockWeb3j).ethGetBlockByNumber(eq(DefaultBlockParameterName.LATEST),
anyBoolean());
+ }
+
@Test
public void ethGetBlockByNumberTest() throws Exception {
EthBlock response = Mockito.mock(EthBlock.class);
@@ -528,15 +559,29 @@ public class Web3jProducerTest extends
Web3jMockTestSupport {
@Test
public void ethGetTransactionReceiptTest() throws Exception {
+ TransactionReceipt receipt = new TransactionReceipt();
+ receipt.setTransactionHash("0x01");
EthGetTransactionReceipt response =
Mockito.mock(EthGetTransactionReceipt.class);
Mockito.when(mockWeb3j.ethGetTransactionReceipt(any())).thenReturn(request);
Mockito.when(request.send()).thenReturn(response);
-
Mockito.when(response.getTransactionReceipt()).thenReturn(Mockito.mock(Optional.class));
+
Mockito.when(response.getTransactionReceipt()).thenReturn(Optional.of(receipt));
Exchange exchange = createExchangeWithBodyAndHeader(null, OPERATION,
Web3jConstants.ETH_GET_TRANSACTION_RECEIPT);
template.send(exchange);
- Optional<Transaction> body = exchange.getIn().getBody(Optional.class);
- assertNotNull(body);
+ assertSame(receipt, exchange.getIn().getBody());
+ }
+
+ @Test
+ public void ethGetTransactionReceiptNotFoundTest() throws Exception {
+ EthGetTransactionReceipt response =
Mockito.mock(EthGetTransactionReceipt.class);
+
Mockito.when(mockWeb3j.ethGetTransactionReceipt(any())).thenReturn(request);
+ Mockito.when(request.send()).thenReturn(response);
+
Mockito.when(response.getTransactionReceipt()).thenReturn(Optional.empty());
+
+ Exchange exchange = createExchangeWithBodyAndHeader("hash", OPERATION,
Web3jConstants.ETH_GET_TRANSACTION_RECEIPT);
+ template.send(exchange);
+ assertNull(exchange.getException());
+ assertNull(exchange.getIn().getBody());
}
@Test
@@ -948,12 +993,22 @@ public class Web3jProducerTest extends
Web3jMockTestSupport {
assertEquals("error data",
exchange.getIn().getHeader(Web3jConstants.ERROR_DATA, String.class));
}
+ @Test
+ public void producerWithoutOperationTest() {
+ Exchange exchange = template.send("direct:noOperation", e ->
e.getIn().setBody("hello"));
+ IllegalArgumentException e =
assertInstanceOf(IllegalArgumentException.class, exchange.getException());
+ assertEquals("No operation for the web3j producer: set the operation
option or the CamelWeb3jOperation header",
+ e.getMessage());
+ }
+
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
public void configure() {
from("direct:start")
.to(getUrl() + "operation" + "=" +
Web3jConstants.WEB3_CLIENT_VERSION);
+ from("direct:noOperation")
+ .to("web3j://http://127.0.0.1:8545?web3j=#mockWeb3j");
}
};
}
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 4758c945a4bb..6155b4596898 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -2774,6 +2774,22 @@ subscription are not routed. `REPLAY_BLOCKS_OBSERVABLE`,
`REPLAY_TRANSACTIONS_OB
`ETH_LOG_OBSERVABLE` with `fromBlock` set to a block number are not subscribed
again, as that would route the same
blocks or logs again.
+=== camel-web3j - ETH_GET_TRANSACTION_RECEIPT gives the TransactionReceipt,
and the block options default to latest
+
+The `ETH_GET_TRANSACTION_RECEIPT` operation now sets the `TransactionReceipt`
as the body, or `null` when the node has no
+receipt for the transaction, like the `ETH_GET_TRANSACTION_BY_*` operations do
with the `Transaction`. Before, the body
+was an `Optional<TransactionReceipt>`: a route that unwraps the `Optional`
must now use the body as it is.
+
+The `atBlock`, `fromBlock` and `toBlock` options now default to `latest`, as
documented. Before, they were not set, and
+the operations that take a block, such as `ETH_GET_BALANCE` and
`ETH_GET_BLOCK_BY_NUMBER`, failed with a
+`NullPointerException` unless `atBlock` or the `CamelWeb3jAtBlock` header was
set, and so did the
+`REPLAY_BLOCKS_OBSERVABLE` and `REPLAY_TRANSACTIONS_OBSERVABLE` consumers
without `fromBlock` and `toBlock`.
+
+The `operation` option defaults to `transaction`, which is not an operation of
the producer nor of the consumer. A
+consumer without an observable operation now fails to start with a message
that lists them, and accepts the operation
+in lower case, as the producer does. A producer without the option and without
the `CamelWeb3jOperation` header now
+fails the exchange with a message that asks for one.
+
=== camel-google-vertexai - generateMultimodal sends the body as media, and
fails without a MIME type
When the `CamelGoogleVertexAIMediaData` and `CamelGoogleVertexAIMediaGcsUri`
headers are not set, the `generateMultimodal`
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/Web3jComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/Web3jComponentBuilderFactory.java
index efeabad9248b..8a01f4e22649 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/Web3jComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/Web3jComponentBuilderFactory.java
@@ -149,7 +149,13 @@ public interface Web3jComponentBuilderFactory {
/**
- * Operation to use.
+ * Operation to use. The producer needs an operation, set with this
+ * option or the CamelWeb3jOperation header. The consumer needs one of
+ * the observable operations: ETH_LOG_OBSERVABLE,
+ * ETH_BLOCK_HASH_OBSERVABLE, ETH_PENDING_TRANSACTION_HASH_OBSERVABLE,
+ * TRANSACTION_OBSERVABLE, PENDING_TRANSACTION_OBSERVABLE,
+ * BLOCK_OBSERVABLE, REPLAY_BLOCKS_OBSERVABLE or
+ * REPLAY_TRANSACTIONS_OBSERVABLE.
*
* The option is a: <code>java.lang.String</code> type.
*
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/Web3jEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/Web3jEndpointBuilderFactory.java
index 5f8090099565..de53e2fa680e 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/Web3jEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/Web3jEndpointBuilderFactory.java
@@ -149,7 +149,13 @@ public interface Web3jEndpointBuilderFactory {
return this;
}
/**
- * Operation to use.
+ * Operation to use. The producer needs an operation, set with this
+ * option or the CamelWeb3jOperation header. The consumer needs one of
+ * the observable operations: ETH_LOG_OBSERVABLE,
+ * ETH_BLOCK_HASH_OBSERVABLE, ETH_PENDING_TRANSACTION_HASH_OBSERVABLE,
+ * TRANSACTION_OBSERVABLE, PENDING_TRANSACTION_OBSERVABLE,
+ * BLOCK_OBSERVABLE, REPLAY_BLOCKS_OBSERVABLE or
+ * REPLAY_TRANSACTIONS_OBSERVABLE.
*
* The option is a: <code>java.lang.String</code> type.
*
@@ -528,7 +534,13 @@ public interface Web3jEndpointBuilderFactory {
return this;
}
/**
- * Operation to use.
+ * Operation to use. The producer needs an operation, set with this
+ * option or the CamelWeb3jOperation header. The consumer needs one of
+ * the observable operations: ETH_LOG_OBSERVABLE,
+ * ETH_BLOCK_HASH_OBSERVABLE, ETH_PENDING_TRANSACTION_HASH_OBSERVABLE,
+ * TRANSACTION_OBSERVABLE, PENDING_TRANSACTION_OBSERVABLE,
+ * BLOCK_OBSERVABLE, REPLAY_BLOCKS_OBSERVABLE or
+ * REPLAY_TRANSACTIONS_OBSERVABLE.
*
* The option is a: <code>java.lang.String</code> type.
*
@@ -1256,7 +1268,13 @@ public interface Web3jEndpointBuilderFactory {
return this;
}
/**
- * Operation to use.
+ * Operation to use. The producer needs an operation, set with this
+ * option or the CamelWeb3jOperation header. The consumer needs one of
+ * the observable operations: ETH_LOG_OBSERVABLE,
+ * ETH_BLOCK_HASH_OBSERVABLE, ETH_PENDING_TRANSACTION_HASH_OBSERVABLE,
+ * TRANSACTION_OBSERVABLE, PENDING_TRANSACTION_OBSERVABLE,
+ * BLOCK_OBSERVABLE, REPLAY_BLOCKS_OBSERVABLE or
+ * REPLAY_TRANSACTIONS_OBSERVABLE.
*
* The option is a: <code>java.lang.String</code> type.
*