This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch brow
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 162ae0ea51bb7468e7e141918a07c69dc0a47233
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Mon Sep 9 07:14:40 2024 +0200

    CAMEL-21183: BrowseEndpoint should have limit/filter to optimize returned 
data from component implementations
---
 .../mbean/ManagedBrowsableEndpointMBean.java       |  11 +-
 .../management/mbean/ManagedBrowsableEndpoint.java |  58 +++++-
 .../ManagedBrowsableEndpointAsJSonFileTest.java    |  64 ++++++
 .../ManagedBrowsableEndpointAsJSonTest.java        | 214 +++++++++++++++++++++
 4 files changed, 342 insertions(+), 5 deletions(-)

diff --git 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBrowsableEndpointMBean.java
 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBrowsableEndpointMBean.java
index 979f7ae3eca..208be8ccfa2 100644
--- 
a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBrowsableEndpointMBean.java
+++ 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedBrowsableEndpointMBean.java
@@ -21,7 +21,7 @@ import org.apache.camel.api.management.ManagedOperation;
 
 public interface ManagedBrowsableEndpointMBean extends ManagedEndpointMBean {
 
-    @ManagedAttribute(description = "Maximum number of messages to browse by 
default.")
+    @ManagedAttribute(description = "Maximum number of messages to browse by 
default")
     int getBrowseLimit();
 
     @ManagedOperation(description = "Current number of Exchanges in Queue")
@@ -42,4 +42,13 @@ public interface ManagedBrowsableEndpointMBean extends 
ManagedEndpointMBean {
     @ManagedOperation(description = "Gets the range of messages as XML from 
the queue")
     String browseRangeMessagesAsXml(Integer fromIndex, Integer toIndex, 
Boolean includeBody);
 
+    @ManagedOperation(description = "Get message as JSon from queue by index")
+    String browseMessageAsJSon(Integer index, Boolean includeBody);
+
+    @ManagedOperation(description = "Gets all the messages as JSon from the 
queue")
+    String browseAllMessagesAsJSon(Boolean includeBody);
+
+    @ManagedOperation(description = "Gets the range of messages as JSon from 
the queue")
+    String browseRangeMessagesAsJSon(Integer fromIndex, Integer toIndex, 
Boolean includeBody);
+
 }
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBrowsableEndpoint.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBrowsableEndpoint.java
index d5de701daee..0a6a7c36cef 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBrowsableEndpoint.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedBrowsableEndpoint.java
@@ -24,6 +24,9 @@ import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.api.management.mbean.ManagedBrowsableEndpointMBean;
 import org.apache.camel.spi.BrowsableEndpoint;
 import org.apache.camel.support.MessageHelper;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
 
 @ManagedResource(description = "Managed BrowsableEndpoint")
 public class ManagedBrowsableEndpoint extends ManagedEndpoint implements 
ManagedBrowsableEndpointMBean {
@@ -79,9 +82,8 @@ public class ManagedBrowsableEndpoint extends ManagedEndpoint 
implements Managed
             return null;
         }
 
-        // must use java type with JMX such as java.lang.String
-
-        return exchange.getMessage().getBody(String.class);
+        Message msg = exchange.getMessage();
+        return MessageHelper.extractBodyAsString(msg);
     }
 
     @Override
@@ -97,7 +99,6 @@ public class ManagedBrowsableEndpoint extends ManagedEndpoint 
implements Managed
         }
 
         Message msg = exchange.getMessage();
-
         return MessageHelper.dumpAsXml(msg, includeBody);
     }
 
@@ -136,4 +137,53 @@ public class ManagedBrowsableEndpoint extends 
ManagedEndpoint implements Managed
         return sb.toString();
     }
 
+    @Override
+    public String browseMessageAsJSon(Integer index, Boolean includeBody) {
+        List<Exchange> exchanges = getEndpoint().getExchanges();
+
+        if (index >= exchanges.size()) {
+            return null;
+        }
+        Exchange exchange = exchanges.get(index);
+        if (exchange == null) {
+            return null;
+        }
+
+        Message msg = exchange.getMessage();
+        return MessageHelper.dumpAsJSon(msg, includeBody);
+    }
+
+    @Override
+    public String browseAllMessagesAsJSon(Boolean includeBody) {
+        return browseRangeMessagesAsJSon(0, Integer.MAX_VALUE, includeBody);
+    }
+
+    @Override
+    public String browseRangeMessagesAsJSon(Integer fromIndex, Integer 
toIndex, Boolean includeBody) {
+        if (fromIndex == null) {
+            fromIndex = 0;
+        }
+        if (toIndex == null) {
+            toIndex = Integer.MAX_VALUE;
+        }
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException(
+                    "From index cannot be larger than to index, was: " + 
fromIndex + " > " + toIndex);
+        }
+
+        List<Exchange> exchanges = getEndpoint().getExchanges();
+        if (exchanges.isEmpty()) {
+            return null;
+        }
+
+        JsonArray arr = new JsonArray();
+        for (int i = fromIndex; i < exchanges.size() && i <= toIndex; i++) {
+            Exchange exchange = exchanges.get(i);
+            Message msg = exchange.getMessage();
+            JsonObject jo = MessageHelper.dumpAsJSonObject(msg, false, false, 
includeBody, true, true, true, 128 * 1024);
+            arr.add(jo);
+        }
+        String out = arr.toJson();
+        return Jsoner.prettyPrint(out);
+    }
 }
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedBrowsableEndpointAsJSonFileTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedBrowsableEndpointAsJSonFileTest.java
new file mode 100644
index 00000000000..4abcdcff063
--- /dev/null
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedBrowsableEndpointAsJSonFileTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.management;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static 
org.apache.camel.management.DefaultManagementObjectNameStrategy.TYPE_ENDPOINT;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DisabledOnOs(OS.AIX)
+public class ManagedBrowsableEndpointAsJSonFileTest extends 
ManagementTestSupport {
+
+    @Test
+    public void testBrowseableEndpointAsJSonAllIncludeBody() throws Exception {
+        template.sendBodyAndHeader("direct:start", "Hello World", 
Exchange.FILE_NAME, "hello.txt");
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        ObjectName name = getCamelObjectName(TYPE_ENDPOINT, "file://" + 
testDirectory());
+
+        String out = (String) mbeanServer.invoke(name, 
"browseAllMessagesAsJSon", new Object[] { true },
+                new String[] { "java.lang.Boolean" });
+        assertNotNull(out);
+        log.info(out);
+        assertTrue(out.contains("\"value\": \"Hello World\""));
+        assertTrue(out.contains("\"type\": 
\"org.apache.camel.component.file.GenericFile\""));
+        assertTrue(out.contains("\"value\": \"hello.txt\""));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                context.setUseBreadcrumb(false);
+
+                from("direct:start").to(fileUri());
+            }
+        };
+    }
+
+}
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedBrowsableEndpointAsJSonTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedBrowsableEndpointAsJSonTest.java
new file mode 100644
index 00000000000..b2b5334914c
--- /dev/null
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedBrowsableEndpointAsJSonTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.management;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static 
org.apache.camel.management.DefaultManagementObjectNameStrategy.TYPE_ENDPOINT;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+@DisabledOnOs(OS.AIX)
+public class ManagedBrowsableEndpointAsJSonTest extends ManagementTestSupport {
+
+    @Test
+    public void testBrowseableEndpointAsJSonIncludeBody() throws Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("user", false);
+        headers.put("uid", 123);
+        headers.put("title", "Camel rocks");
+        template.sendBodyAndHeaders("direct:start", "Hello World", headers);
+
+        assertMockEndpointsSatisfied();
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        ObjectName name = getCamelObjectName(TYPE_ENDPOINT, "mock://result");
+
+        String out = (String) mbeanServer.invoke(name, "browseMessageAsJSon", 
new Object[] { 0, true },
+                new String[] { "java.lang.Integer", "java.lang.Boolean" });
+        assertNotNull(out);
+        log.info(out);
+        assertTrue(out.contains("\"body\": {"));
+        assertTrue(out.contains("\"value\": \"Hello World\""));
+    }
+
+    @Test
+    public void testBrowseableEndpointAsJSon() throws Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+
+        template.sendBodyAndHeader("direct:start", "Hello World", "foo", 123);
+        template.sendBodyAndHeader("direct:start", "Bye World", "foo", 456);
+
+        assertMockEndpointsSatisfied();
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        ObjectName name = getCamelObjectName(TYPE_ENDPOINT, "mock://result");
+
+        String out = (String) mbeanServer.invoke(name, "browseMessageAsJSon", 
new Object[] { 0, false },
+                new String[] { "java.lang.Integer", "java.lang.Boolean" });
+        assertNotNull(out);
+        assertFalse(out.contains("\"body\": {"));
+        assertTrue(out.contains("\"value\": 123"));
+
+        out = (String) mbeanServer.invoke(name, "browseMessageAsJSon", new 
Object[] { 1, false },
+                new String[] { "java.lang.Integer", "java.lang.Boolean" });
+        assertNotNull(out);
+        assertFalse(out.contains("\"body\": {"));
+        assertTrue(out.contains("\"value\": 456"));
+    }
+
+    @Test
+    public void testBrowseableEndpointAsJSonAllIncludeBody() throws Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBodyAndHeader("direct:start", "Bye World", "foo", 456);
+
+        assertMockEndpointsSatisfied();
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        ObjectName name = getCamelObjectName(TYPE_ENDPOINT, "mock://result");
+
+        String out = (String) mbeanServer.invoke(name, 
"browseAllMessagesAsJSon", new Object[] { true },
+                new String[] { "java.lang.Boolean" });
+        assertNotNull(out);
+        log.info(out);
+
+        assertTrue(out.contains("\"value\": \"Hello World\""));
+        assertTrue(out.contains("\"value\": \"Bye World\""));
+    }
+
+    @Test
+    public void testBrowseableEndpointAsJSonAll() throws Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+
+        template.sendBodyAndHeader("direct:start", "Hello World", "foo", 123);
+        template.sendBodyAndHeader("direct:start", "Bye World", "foo", 456);
+
+        assertMockEndpointsSatisfied();
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        ObjectName name = getCamelObjectName(TYPE_ENDPOINT, "mock://result");
+
+        String out = (String) mbeanServer.invoke(name, 
"browseAllMessagesAsJSon", new Object[] { false },
+                new String[] { "java.lang.Boolean" });
+        assertNotNull(out);
+        log.info(out);
+
+        assertFalse(out.contains("\"body\": {"));
+        assertTrue(out.contains("\"value\": 123"));
+        assertTrue(out.contains("\"value\": 456"));
+    }
+
+    @Test
+    public void testBrowseableEndpointAsJSonRangeIncludeBody() throws 
Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(3);
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBodyAndHeader("direct:start", "Bye World", "foo", 456);
+        template.sendBody("direct:start", "Hi Camel");
+
+        assertMockEndpointsSatisfied();
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        ObjectName name = getCamelObjectName(TYPE_ENDPOINT, "mock://result");
+
+        String out = (String) mbeanServer.invoke(name, 
"browseRangeMessagesAsJSon", new Object[] { 0, 1, true },
+                new String[] { "java.lang.Integer", "java.lang.Integer", 
"java.lang.Boolean" });
+        assertNotNull(out);
+        log.info(out);
+
+        assertTrue(out.contains("\"value\": \"Hello World\""));
+        assertTrue(out.contains("\"value\": \"Bye World\""));
+    }
+
+    @Test
+    public void testBrowseableEndpointAsJSonRange() throws Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(3);
+
+        template.sendBodyAndHeader("direct:start", "Hello World", "foo", 123);
+        template.sendBodyAndHeader("direct:start", "Bye World", "foo", 456);
+        template.sendBody("direct:start", "Hi Camel");
+
+        assertMockEndpointsSatisfied();
+
+        List<Exchange> exchanges = 
getMockEndpoint("mock:result").getReceivedExchanges();
+
+        MBeanServer mbeanServer = getMBeanServer();
+
+        ObjectName name = getCamelObjectName(TYPE_ENDPOINT, "mock://result");
+
+        String out = (String) mbeanServer.invoke(name, 
"browseRangeMessagesAsJSon", new Object[] { 0, 1, false },
+                new String[] { "java.lang.Integer", "java.lang.Integer", 
"java.lang.Boolean" });
+        assertNotNull(out);
+        log.info(out);
+
+        assertFalse(out.contains("\"body\": {"));
+        assertTrue(out.contains("\"value\": 123"));
+        assertTrue(out.contains("\"value\": 456"));
+    }
+
+    @Test
+    public void testBrowseableEndpointAsJSonRangeInvalidIndex() throws 
Exception {
+        MBeanServer mbeanServer = getMBeanServer();
+
+        ObjectName name = getCamelObjectName(TYPE_ENDPOINT, "mock://result");
+
+        try {
+            mbeanServer.invoke(name, "browseRangeMessagesAsJSon", new Object[] 
{ 3, 1, false },
+                    new String[] { "java.lang.Integer", "java.lang.Integer", 
"java.lang.Boolean" });
+            fail("Should have thrown exception");
+        } catch (Exception e) {
+            assertIsInstanceOf(IllegalArgumentException.class, e.getCause());
+            assertEquals("From index cannot be larger than to index, was: 3 > 
1", e.getCause().getMessage());
+        }
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                context.setUseBreadcrumb(false);
+
+                from("direct:start").to("mock:result");
+            }
+        };
+    }
+
+}

Reply via email to