This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch CAMEL-26156-pubnub-fire-setstate in repository https://gitbox.apache.org/repos/asf/camel.git
commit 1b02c7b1682f5374aa90196828455765be04471f Author: Claus Ibsen <[email protected]> AuthorDate: Mon Nov 2 17:50:42 2026 +0100 CAMEL-26156: camel-pubnub - FIRE and SETSTATE with an empty body fail without calling PubNub, and PNMessageResult converts to String FIRE and SETSTATE set an exception and called the callback when the body was empty, but did not return: the PubNub call still ran and called the callback a second time, and process returned false. They now throw the CamelException as PUBLISH does, so process completes the exchange once, synchronously, without calling PubNub. Add a PubNubConverter so the PNMessageResult body of the consumer converts to a String: a string message as its text, any other message as JSON. Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../apache/camel/catalog/components/pubnub.json | 2 +- .../camel/catalog/docs/pubnub-component.adoc | 3 + .../component/pubnub/PubNubConverterLoader.java | 60 ++++++++++++++ .../org/apache/camel/component/pubnub/pubnub.json | 2 +- .../services/org/apache/camel/TypeConverterLoader | 2 + .../src/main/docs/pubnub-component.adoc | 3 + .../camel/component/pubnub/PubNubConverter.java | 45 +++++++++++ .../camel/component/pubnub/PubNubEndpoint.java | 3 +- .../camel/component/pubnub/PubNubProducer.java | 10 +-- .../component/pubnub/PubNubConverterTest.java | 63 +++++++++++++++ .../component/pubnub/PubNubEmptyBodyTest.java | 92 ++++++++++++++++++++++ .../component/pubnub/PubNubSubscriberTest.java | 3 + .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 9 +++ 13 files changed, 288 insertions(+), 9 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pubnub.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pubnub.json index e4d1181ad220..8f1b477e5a07 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pubnub.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pubnub.json @@ -45,7 +45,7 @@ "CamelPubNubUUID": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "UUID to be used as a device identifier.", "constantName": "org.apache.camel.component.pubnub.PubNubConstants#UUID" } }, "bodyTypes": { - "consumerOut": { "carriers": [ "pojo" ], "javaType": "com.pubnub.api.models.consumer.pubsub.PNMessageResult", "byOption": [ { "option": "withPresence", "value": "true", "carriers": [ "pojo" ] } ], "description": "The PubNub PNMessageResult; its getMessage() is the payload as a Gson JsonElement, and it does not convert to the payload text. With withPresence, a presence event comes as a PNPresenceEventResult. The channel and timetoken are in the CamelPubNubChannel and CamelPubNubTimeTo [...] + "consumerOut": { "carriers": [ "pojo" ], "javaType": "com.pubnub.api.models.consumer.pubsub.PNMessageResult", "byOption": [ { "option": "withPresence", "value": "true", "carriers": [ "pojo" ] } ], "description": "The PubNub PNMessageResult; its getMessage() is the payload as a Gson JsonElement. It converts to a String: a string message as its text, any other message as JSON. With withPresence, a presence event comes as a PNPresenceEventResult. The channel and timetoken are in the Cam [...] "producerIn": { "carriers": [ "text", "value", "map", "list", "pojo" ], "byOption": [ { "option": "operation", "value": "SETSTATE", "carriers": [ "map", "pojo" ] }, { "option": "operation", "value": "GETHISTORY", "carriers": [ "any" ] }, { "option": "operation", "value": "GETSTATE", "carriers": [ "any" ] }, { "option": "operation", "value": "HERENOW", "carriers": [ "any" ] } ], "description": "The message to publish or fire, serialized to JSON by the PubNub client: text is sent as a [...] "producerOut": { "carriers": [ "unchanged" ], "byOption": [ { "option": "operation", "value": "GETHISTORY", "carriers": [ "list", "unchanged" ] }, { "option": "operation", "value": "GETSTATE", "carriers": [ "pojo" ], "javaType": "com.pubnub.api.models.consumer.presence.PNGetStateResult" }, { "option": "operation", "value": "HERENOW", "carriers": [ "pojo" ], "javaType": "com.pubnub.api.models.consumer.presence.PNHereNowResult" }, { "option": "operation", "value": "SETSTATE", "carriers [...] }, diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pubnub-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pubnub-component.adoc index c99ce1395990..68dbe084c4ef 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pubnub-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pubnub-component.adoc @@ -64,6 +64,9 @@ Pass the full object as the message payload. PubNub will take care of object serialization. When receiving the message body uses objects provided by the PubNub API. +A message is a `PNMessageResult`, and `getMessage()` is the payload as a Gson `JsonElement`. +The `PNMessageResult` converts to a `String`, so `${body}` or `convertBodyTo(String.class)` gives the payload: +a string message as its text, and any other message (an object, an array, a number) as JSON. == Examples diff --git a/components/camel-pubnub/src/generated/java/org/apache/camel/component/pubnub/PubNubConverterLoader.java b/components/camel-pubnub/src/generated/java/org/apache/camel/component/pubnub/PubNubConverterLoader.java new file mode 100644 index 000000000000..32df8f30563d --- /dev/null +++ b/components/camel-pubnub/src/generated/java/org/apache/camel/component/pubnub/PubNubConverterLoader.java @@ -0,0 +1,60 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.pubnub; + +import javax.annotation.processing.Generated; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.DeferredContextBinding; +import org.apache.camel.Exchange; +import org.apache.camel.TypeConversionException; +import org.apache.camel.TypeConverterLoaderException; +import org.apache.camel.spi.TypeConverterLoader; +import org.apache.camel.spi.TypeConverterRegistry; +import org.apache.camel.support.SimpleTypeConverter; +import org.apache.camel.support.TypeConverterSupport; +import org.apache.camel.util.DoubleMap; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.TypeConverterLoaderGeneratorMojo") +@SuppressWarnings("unchecked") +@DeferredContextBinding +public final class PubNubConverterLoader implements TypeConverterLoader, CamelContextAware { + + private CamelContext camelContext; + + public PubNubConverterLoader() { + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void load(TypeConverterRegistry registry) throws TypeConverterLoaderException { + registerConverters(registry); + } + + private void registerConverters(TypeConverterRegistry registry) { + addTypeConverter(registry, java.lang.String.class, com.pubnub.api.models.consumer.pubsub.PNMessageResult.class, false, + (type, exchange, value) -> { + Object answer = org.apache.camel.component.pubnub.PubNubConverter.toString((com.pubnub.api.models.consumer.pubsub.PNMessageResult) value); + if (false && answer == null) { + answer = Void.class; + } + return answer; + }); + } + + private static void addTypeConverter(TypeConverterRegistry registry, Class<?> toType, Class<?> fromType, boolean allowNull, SimpleTypeConverter.ConversionMethod method) { + registry.addTypeConverter(toType, fromType, new SimpleTypeConverter(allowNull, method)); + } +} diff --git a/components/camel-pubnub/src/generated/resources/META-INF/org/apache/camel/component/pubnub/pubnub.json b/components/camel-pubnub/src/generated/resources/META-INF/org/apache/camel/component/pubnub/pubnub.json index e4d1181ad220..8f1b477e5a07 100644 --- a/components/camel-pubnub/src/generated/resources/META-INF/org/apache/camel/component/pubnub/pubnub.json +++ b/components/camel-pubnub/src/generated/resources/META-INF/org/apache/camel/component/pubnub/pubnub.json @@ -45,7 +45,7 @@ "CamelPubNubUUID": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "UUID to be used as a device identifier.", "constantName": "org.apache.camel.component.pubnub.PubNubConstants#UUID" } }, "bodyTypes": { - "consumerOut": { "carriers": [ "pojo" ], "javaType": "com.pubnub.api.models.consumer.pubsub.PNMessageResult", "byOption": [ { "option": "withPresence", "value": "true", "carriers": [ "pojo" ] } ], "description": "The PubNub PNMessageResult; its getMessage() is the payload as a Gson JsonElement, and it does not convert to the payload text. With withPresence, a presence event comes as a PNPresenceEventResult. The channel and timetoken are in the CamelPubNubChannel and CamelPubNubTimeTo [...] + "consumerOut": { "carriers": [ "pojo" ], "javaType": "com.pubnub.api.models.consumer.pubsub.PNMessageResult", "byOption": [ { "option": "withPresence", "value": "true", "carriers": [ "pojo" ] } ], "description": "The PubNub PNMessageResult; its getMessage() is the payload as a Gson JsonElement. It converts to a String: a string message as its text, any other message as JSON. With withPresence, a presence event comes as a PNPresenceEventResult. The channel and timetoken are in the Cam [...] "producerIn": { "carriers": [ "text", "value", "map", "list", "pojo" ], "byOption": [ { "option": "operation", "value": "SETSTATE", "carriers": [ "map", "pojo" ] }, { "option": "operation", "value": "GETHISTORY", "carriers": [ "any" ] }, { "option": "operation", "value": "GETSTATE", "carriers": [ "any" ] }, { "option": "operation", "value": "HERENOW", "carriers": [ "any" ] } ], "description": "The message to publish or fire, serialized to JSON by the PubNub client: text is sent as a [...] "producerOut": { "carriers": [ "unchanged" ], "byOption": [ { "option": "operation", "value": "GETHISTORY", "carriers": [ "list", "unchanged" ] }, { "option": "operation", "value": "GETSTATE", "carriers": [ "pojo" ], "javaType": "com.pubnub.api.models.consumer.presence.PNGetStateResult" }, { "option": "operation", "value": "HERENOW", "carriers": [ "pojo" ], "javaType": "com.pubnub.api.models.consumer.presence.PNHereNowResult" }, { "option": "operation", "value": "SETSTATE", "carriers [...] }, diff --git a/components/camel-pubnub/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader b/components/camel-pubnub/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader new file mode 100644 index 000000000000..851225edb141 --- /dev/null +++ b/components/camel-pubnub/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +org.apache.camel.component.pubnub.PubNubConverterLoader diff --git a/components/camel-pubnub/src/main/docs/pubnub-component.adoc b/components/camel-pubnub/src/main/docs/pubnub-component.adoc index c99ce1395990..68dbe084c4ef 100644 --- a/components/camel-pubnub/src/main/docs/pubnub-component.adoc +++ b/components/camel-pubnub/src/main/docs/pubnub-component.adoc @@ -64,6 +64,9 @@ Pass the full object as the message payload. PubNub will take care of object serialization. When receiving the message body uses objects provided by the PubNub API. +A message is a `PNMessageResult`, and `getMessage()` is the payload as a Gson `JsonElement`. +The `PNMessageResult` converts to a `String`, so `${body}` or `convertBodyTo(String.class)` gives the payload: +a string message as its text, and any other message (an object, an array, a number) as JSON. == Examples diff --git a/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubConverter.java b/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubConverter.java new file mode 100644 index 000000000000..bdd908389c5f --- /dev/null +++ b/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubConverter.java @@ -0,0 +1,45 @@ +/* + * 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.pubnub; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.pubnub.api.models.consumer.pubsub.PNMessageResult; +import org.apache.camel.Converter; + +/** + * Converts the PubNub objects the consumer sets as the message body. + */ +@Converter(generateLoader = true) +public final class PubNubConverter { + + private PubNubConverter() { + } + + /** + * The payload of a received PubNub message as text: a string message as its text, any other message (a JSON object, + * array, number or boolean) as JSON. + */ + @Converter + public static String toString(PNMessageResult message) { + JsonElement payload = message.getMessage(); + if (payload instanceof JsonPrimitive primitive && primitive.isString()) { + return primitive.getAsString(); + } + return payload.toString(); + } +} diff --git a/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubEndpoint.java b/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubEndpoint.java index 24e56b3438ad..d8ab8417d30f 100644 --- a/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubEndpoint.java +++ b/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubEndpoint.java @@ -42,7 +42,8 @@ import org.apache.camel.support.DefaultEndpoint; byOption = @BodyType.When(option = "withPresence", value = "true", carriers = Carrier.POJO), description = "The PubNub PNMessageResult; its getMessage() is the payload as a Gson" - + " JsonElement, and it does not convert to the payload text. With" + + " JsonElement. It converts to a String: a string message as its text," + + " any other message as JSON. With" + " withPresence, a presence event comes as a PNPresenceEventResult. The" + " channel and timetoken are in the CamelPubNubChannel and" + " CamelPubNubTimeToken headers"), diff --git a/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubProducer.java b/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubProducer.java index 54c0cb402169..3af2d7bcc5fe 100644 --- a/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubProducer.java +++ b/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubProducer.java @@ -123,11 +123,10 @@ public class PubNubProducer extends DefaultAsyncProducer { }); } - private void doFire(Exchange exchange, AsyncCallback callback) { + private void doFire(Exchange exchange, AsyncCallback callback) throws CamelException { Object body = exchange.getIn().getBody(); if (ObjectHelper.isEmpty(body)) { - exchange.setException(new CamelException("Can not fire empty message")); - callback.done(true); + throw new CamelException("Can not fire empty message"); } LOG.debug("Sending message [{}] to channel [{}]", body, getChannel(exchange)); endpoint.getPubnub() @@ -171,11 +170,10 @@ public class PubNubProducer extends DefaultAsyncProducer { }); } - private void doSetState(Exchange exchange, AsyncCallback callback) { + private void doSetState(Exchange exchange, AsyncCallback callback) throws CamelException { Object body = exchange.getIn().getBody(); if (ObjectHelper.isEmpty(body)) { - exchange.setException(new CamelException("Can not publish empty message")); - callback.done(true); + throw new CamelException("Can not publish empty message"); } LOG.debug("Sending setState [{}] to channel [{}]", body, getChannel(exchange)); endpoint.getPubnub() diff --git a/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubConverterTest.java b/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubConverterTest.java new file mode 100644 index 000000000000..1f898f5e2bc0 --- /dev/null +++ b/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubConverterTest.java @@ -0,0 +1,63 @@ +/* + * 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.pubnub; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.pubnub.api.models.consumer.pubsub.BasePubSubResult; +import com.pubnub.api.models.consumer.pubsub.PNMessageResult; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PubNubConverterTest extends CamelTestSupport { + + @Test + public void testStringMessageToString() { + assertEquals("Hello World", convert(new JsonPrimitive("Hello World"))); + } + + @Test + public void testObjectMessageToString() { + JsonObject json = new JsonObject(); + json.addProperty("text", "Message"); + json.addProperty("count", 3); + assertEquals("{\"text\":\"Message\",\"count\":3}", convert(json)); + } + + @Test + public void testArrayMessageToString() { + JsonArray json = new JsonArray(); + json.add("a"); + json.add(1); + assertEquals("[\"a\",1]", convert(json)); + } + + @Test + public void testNumberMessageToString() { + assertEquals("42", convert(new JsonPrimitive(42))); + } + + private String convert(JsonElement payload) { + PNMessageResult message = new PNMessageResult( + new BasePubSubResult("mychannel", null, 14607577960932487L, null, "publisher"), payload, null, null); + return context.getTypeConverter().convertTo(String.class, message); + } +} diff --git a/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubEmptyBodyTest.java b/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubEmptyBodyTest.java new file mode 100644 index 000000000000..69ab08fc4927 --- /dev/null +++ b/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubEmptyBodyTest.java @@ -0,0 +1,92 @@ +/* + * 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.pubnub; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.camel.AsyncProducer; +import org.apache.camel.CamelException; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.support.DefaultExchange; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static com.github.tomakehurst.wiremock.client.WireMock.anyRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * FIRE and SETSTATE with an empty body fail without calling PubNub, like PUBLISH. + */ +public class PubNubEmptyBodyTest extends PubNubTestBase { + + @Test + public void testFireNullBody() { + Exchange exchange = template.request("direct:fire", e -> e.getIn().setBody(null)); + + CamelException cause = assertInstanceOf(CamelException.class, exchange.getException()); + assertEquals("Can not fire empty message", cause.getMessage()); + verify(0, anyRequestedFor(anyUrl())); + } + + @Test + public void testSetStateEmptyBody() { + Exchange exchange = template.request("direct:setstate", e -> e.getIn().setBody(Map.of())); + + CamelException cause = assertInstanceOf(CamelException.class, exchange.getException()); + assertEquals("Can not publish empty message", cause.getMessage()); + verify(0, anyRequestedFor(anyUrl())); + } + + @ParameterizedTest + @ValueSource(strings = { "FIRE", "SETSTATE" }) + public void testEmptyBodyCompletesSynchronouslyOnce(String operation) throws Exception { + AsyncProducer producer = context.getEndpoint("pubnub:someChannel?uuid=myuuid&pubnub=#pubnub").createAsyncProducer(); + producer.start(); + try { + Exchange exchange = new DefaultExchange(context); + exchange.getIn().setHeader(PubNubConstants.OPERATION, operation); + AtomicInteger doneSync = new AtomicInteger(); + AtomicInteger doneAsync = new AtomicInteger(); + + boolean sync = producer.process(exchange, ds -> (ds ? doneSync : doneAsync).incrementAndGet()); + + assertTrue(sync, "process must return true as the callback was called synchronously"); + assertEquals(1, doneSync.get()); + assertEquals(0, doneAsync.get()); + assertInstanceOf(CamelException.class, exchange.getException()); + } finally { + producer.stop(); + } + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:fire").to("pubnub:someChannel?operation=fire&pubnub=#pubnub"); + from("direct:setstate").to("pubnub:someChannel?operation=setstate&uuid=myuuid&pubnub=#pubnub"); + } + }; + } +} diff --git a/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubSubscriberTest.java b/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubSubscriberTest.java index 5caf4c9cdda8..382d9b82b572 100644 --- a/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubSubscriberTest.java +++ b/components/camel-pubnub/src/test/java/org/apache/camel/component/pubnub/PubNubSubscriberTest.java @@ -25,6 +25,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static org.junit.jupiter.api.Assertions.assertEquals; public class PubNubSubscriberTest extends PubNubTestBase { @@ -45,6 +46,8 @@ public class PubNubSubscriberTest extends PubNubTestBase { mockResult.expectedMessageCount(1); mockResult.expectedHeaderReceived(PubNubConstants.CHANNEL, "mychannel"); MockEndpoint.assertIsSatisfied(context); + // the PNMessageResult body converts to the JSON of the message + assertEquals("{\"text\":\"Message\"}", mockResult.getReceivedExchanges().get(0).getIn().getBody(String.class)); } @Override 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 1bc188419d61..4aacd03a9ed6 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 @@ -895,6 +895,15 @@ the same JVM. An application that relied on the providers being de-registered on shutdown must now remove them itself with `Security.removeProvider("BC")` and `Security.removeProvider("BCPQC")`. +=== camel-pubnub - FIRE and SETSTATE with an empty body fail without calling PubNub + +The `FIRE` and `SETSTATE` operations with an empty body now fail with a `CamelException` (`Can not fire empty +message` or `Can not publish empty message`) and do not call PubNub, as `PUBLISH` does. Before, the call to PubNub +still ran, so `FIRE` with a null body could end with the `PubNubException` `Message Missing` instead. + +The `PNMessageResult` body of the consumer now converts to a `String`: a string message as its text, any other message +as JSON. Before, the conversion gave the `toString()` of the `PNMessageResult` object. + === camel-jbang - camel validate normalize writes one file per input file to an output directory `camel validate normalize <files> --output=<dir>` now writes one normalized file per input file into the
