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

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

commit 461c08bd1e2088bf43892c548633900a395ee3d8
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Feb 1 20:02:43 2026 +0100

    CAMEL-22935: Add JMX for simple function repository
---
 .../apache/camel/catalog/dev-consoles.properties   |  1 +
 .../catalog/dev-consoles/simple-language.json      | 15 +++++
 .../apache/camel/spi/SimpleFunctionRegistry.java   |  3 +-
 .../apache/camel/dev-console/simple-language.json  | 15 +++++
 .../org/apache/camel/dev-console/simple-language   |  2 +
 .../org/apache/camel/dev-consoles.properties       |  2 +-
 .../camel/impl/console/SimpleLanguageConsole.java  | 62 +++++++++++++++++
 .../impl/console/SimpleLanguageDevConsoleTest.java | 52 +++++++++++++++
 .../simple/ast/SimpleFunctionExpression.java       |  2 +-
 .../mbean/ManagedSimpleFunctionRegistryMBean.java} | 44 +++----------
 .../management/JmxManagementLifecycleStrategy.java |  4 ++
 .../mbean/ManagedSimpleFunctionRepository.java     | 50 ++++++++++++++
 .../ManagedSimpleFunctionRegistryTest.java         | 77 ++++++++++++++++++++++
 13 files changed, 291 insertions(+), 38 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles.properties
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles.properties
index 482964cf14ff..eccfcfb03b00 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles.properties
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles.properties
@@ -47,6 +47,7 @@ route-structure
 send
 service
 sftp
+simple-language
 source
 startup-recorder
 stub
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/simple-language.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/simple-language.json
new file mode 100644
index 000000000000..574bed5374d6
--- /dev/null
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/simple-language.json
@@ -0,0 +1,15 @@
+{
+  "console": {
+    "kind": "console",
+    "group": "camel",
+    "name": "simple-language",
+    "title": "Simple Language",
+    "description": "Display simple language details",
+    "deprecated": false,
+    "javaType": "org.apache.camel.impl.console.SimpleLanguageConsole",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-console",
+    "version": "4.18.0-SNAPSHOT"
+  }
+}
+
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/SimpleFunctionRegistry.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/SimpleFunctionRegistry.java
index 1eb3f9fa66af..ea594014d5f5 100644
--- 
a/core/camel-api/src/main/java/org/apache/camel/spi/SimpleFunctionRegistry.java
+++ 
b/core/camel-api/src/main/java/org/apache/camel/spi/SimpleFunctionRegistry.java
@@ -19,11 +19,12 @@ package org.apache.camel.spi;
 import java.util.Set;
 
 import org.apache.camel.Expression;
+import org.apache.camel.StaticService;
 
 /**
  * Registry for custom simple functions.
  */
-public interface SimpleFunctionRegistry {
+public interface SimpleFunctionRegistry extends StaticService {
 
     /**
      * Add a function
diff --git 
a/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/simple-language.json
 
b/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/simple-language.json
new file mode 100644
index 000000000000..574bed5374d6
--- /dev/null
+++ 
b/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/simple-language.json
@@ -0,0 +1,15 @@
+{
+  "console": {
+    "kind": "console",
+    "group": "camel",
+    "name": "simple-language",
+    "title": "Simple Language",
+    "description": "Display simple language details",
+    "deprecated": false,
+    "javaType": "org.apache.camel.impl.console.SimpleLanguageConsole",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-console",
+    "version": "4.18.0-SNAPSHOT"
+  }
+}
+
diff --git 
a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/simple-language
 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/simple-language
new file mode 100644
index 000000000000..347f59529c4f
--- /dev/null
+++ 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/simple-language
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.console.SimpleLanguageConsole
diff --git 
a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-consoles.properties
 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-consoles.properties
index 65578a3c3840..d1f4d2b43665 100644
--- 
a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-consoles.properties
+++ 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-consoles.properties
@@ -1,5 +1,5 @@
 # Generated by camel build tools - do NOT edit this file!
-dev-consoles=bean blocked browse circuit-breaker consumer context debug 
endpoint event gc health inflight internal-tasks java-security jvm log memory 
message-history processor producer properties receive reload rest route 
route-controller route-dump route-group route-structure send service source 
startup-recorder system-properties thread top trace transformers 
type-converters variables
+dev-consoles=bean blocked browse circuit-breaker consumer context debug 
endpoint event gc health inflight internal-tasks java-security jvm log memory 
message-history processor producer properties receive reload rest route 
route-controller route-dump route-group route-structure send service 
simple-language source startup-recorder system-properties thread top trace 
transformers type-converters variables
 groupId=org.apache.camel
 artifactId=camel-console
 version=4.18.0-SNAPSHOT
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/SimpleLanguageConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/SimpleLanguageConsole.java
new file mode 100644
index 000000000000..d32421c14ce2
--- /dev/null
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/SimpleLanguageConsole.java
@@ -0,0 +1,62 @@
+/*
+ * 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.impl.console;
+
+import java.util.Map;
+
+import org.apache.camel.spi.SimpleFunctionRegistry;
+import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.support.PluginHelper;
+import org.apache.camel.support.console.AbstractDevConsole;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+
+@DevConsole(name = "simple-language", displayName = "Simple Language", 
description = "Display simple language details")
+public class SimpleLanguageConsole extends AbstractDevConsole {
+
+    public SimpleLanguageConsole() {
+        super("camel", "simple-language", "Simple Language", "Display simple 
language details");
+    }
+
+    @Override
+    protected String doCallText(Map<String, Object> options) {
+        StringBuilder sb = new StringBuilder();
+
+        SimpleFunctionRegistry reg = 
PluginHelper.getSimpleFunctionRegistry(getCamelContext());
+        sb.append(String.format("%n    Custom Functions: %d", reg.size()));
+        for (String name : reg.getFunctionNames()) {
+            sb.append(String.format("%n    %s", name));
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        SimpleFunctionRegistry reg = 
PluginHelper.getSimpleFunctionRegistry(getCamelContext());
+
+        JsonObject root = new JsonObject();
+        root.put("size", reg.size());
+        JsonArray arr = new JsonArray();
+        arr.addAll(reg.getFunctionNames());
+        if (!arr.isEmpty()) {
+            root.put("functions", arr);
+        }
+
+        return root;
+    }
+}
diff --git 
a/core/camel-console/src/test/java/org/apache/camel/impl/console/SimpleLanguageDevConsoleTest.java
 
b/core/camel-console/src/test/java/org/apache/camel/impl/console/SimpleLanguageDevConsoleTest.java
new file mode 100644
index 000000000000..ae79db9056ce
--- /dev/null
+++ 
b/core/camel-console/src/test/java/org/apache/camel/impl/console/SimpleLanguageDevConsoleTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.impl.console;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.console.DevConsole;
+import org.apache.camel.support.PluginHelper;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class SimpleLanguageDevConsoleTest extends ContextTestSupport {
+
+    @Test
+    public void testSimpleLanguageTest() {
+        DevConsole con = 
PluginHelper.getDevConsoleResolver(context).resolveDevConsole("simple-language");
+        Assertions.assertNotNull(con);
+        Assertions.assertEquals("camel", con.getGroup());
+        Assertions.assertEquals("simple-language", con.getId());
+
+        String out = (String) con.call(DevConsole.MediaType.TEXT);
+        Assertions.assertNotNull(out);
+        Assertions.assertTrue(out.contains("Custom Functions: 0"));
+    }
+
+    @Test
+    public void testSimpleLanguageJson() {
+        DevConsole con = 
PluginHelper.getDevConsoleResolver(context).resolveDevConsole("simple-language");
+        Assertions.assertNotNull(con);
+        Assertions.assertEquals("camel", con.getGroup());
+        Assertions.assertEquals("simple-language", con.getId());
+
+        JsonObject out = (JsonObject) con.call(DevConsole.MediaType.JSON);
+        Assertions.assertEquals(0, out.getInteger("size"));
+        Assertions.assertNotNull(out);
+    }
+
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index b53b4a9f6899..c5b624b4ba88 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -375,7 +375,7 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         String name = StringHelper.before(function, "(", function);
         if 
(PluginHelper.getSimpleFunctionRegistry(camelContext).getFunctionNames().contains(name))
 {
             String after = StringHelper.after(function, "(");
-            if (after.equals(")")) {
+            if (after == null || after.equals(")")) {
                 function = "function(" + name + ")";
             } else {
                 function = "function(" + name + "," + after;
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/SimpleFunctionRegistry.java 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedSimpleFunctionRegistryMBean.java
similarity index 51%
copy from 
core/camel-api/src/main/java/org/apache/camel/spi/SimpleFunctionRegistry.java
copy to 
core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedSimpleFunctionRegistryMBean.java
index 1eb3f9fa66af..f1c687932fcd 100644
--- 
a/core/camel-api/src/main/java/org/apache/camel/spi/SimpleFunctionRegistry.java
+++ 
b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedSimpleFunctionRegistryMBean.java
@@ -14,48 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.spi;
+package org.apache.camel.api.management.mbean;
 
 import java.util.Set;
 
-import org.apache.camel.Expression;
+import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedOperation;
 
-/**
- * Registry for custom simple functions.
- */
-public interface SimpleFunctionRegistry {
-
-    /**
-     * Add a function
-     *
-     * @param name       name of function
-     * @param expression the expression to use as the function
-     */
-    void addFunction(String name, Expression expression);
-
-    /**
-     * Remove a function
-     *
-     * @param name name of function
-     */
-    void removeFunction(String name);
+public interface ManagedSimpleFunctionRegistryMBean extends 
ManagedServiceMBean {
 
-    /**
-     * Gets the function
-     *
-     * @param  name name of function
-     * @return      the function, or <tt>null</tt> if no function exists
-     */
-    Expression getFunction(String name);
+    @ManagedAttribute(description = "Number of custom functions")
+    int getSize();
 
-    /**
-     * Returns a set with all the function names
-     */
+    @ManagedAttribute(description = "The names of the custom functions")
     Set<String> getFunctionNames();
 
-    /**
-     * Number of custom functions
-     */
-    int size();
+    @ManagedOperation(description = "Is there a custom function with the given 
name")
+    boolean hasFunction(String name);
 
 }
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
index 9770c932c4de..f654deaa3eaf 100644
--- 
a/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/JmxManagementLifecycleStrategy.java
@@ -71,6 +71,7 @@ import org.apache.camel.management.mbean.ManagedRouteGroup;
 import org.apache.camel.management.mbean.ManagedRuntimeEndpointRegistry;
 import org.apache.camel.management.mbean.ManagedService;
 import org.apache.camel.management.mbean.ManagedShutdownStrategy;
+import org.apache.camel.management.mbean.ManagedSimpleFunctionRepository;
 import org.apache.camel.management.mbean.ManagedStreamCachingStrategy;
 import org.apache.camel.management.mbean.ManagedTaskManagerRegistry;
 import org.apache.camel.management.mbean.ManagedThrottlingExceptionRoutePolicy;
@@ -109,6 +110,7 @@ import org.apache.camel.spi.ProducerCache;
 import org.apache.camel.spi.RestRegistry;
 import org.apache.camel.spi.RuntimeEndpointRegistry;
 import org.apache.camel.spi.ShutdownStrategy;
+import org.apache.camel.spi.SimpleFunctionRegistry;
 import org.apache.camel.spi.StreamCachingStrategy;
 import org.apache.camel.spi.Tracer;
 import org.apache.camel.spi.TransformerRegistry;
@@ -600,6 +602,8 @@ public class JmxManagementLifecycleStrategy extends 
ServiceSupport implements Li
             answer = new ManagedTaskManagerRegistry(camelContext, registry);
         } else if (service instanceof CamelClusterService camelClusterService) 
{
             answer = 
getManagementObjectStrategy().getManagedObjectForClusterService(context, 
camelClusterService);
+        } else if (service instanceof SimpleFunctionRegistry registry) {
+            answer = new ManagedSimpleFunctionRepository(context, registry);
         } else if (service != null) {
             // fallback as generic service
             answer = 
getManagementObjectStrategy().getManagedObjectForService(context, service);
diff --git 
a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSimpleFunctionRepository.java
 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSimpleFunctionRepository.java
new file mode 100644
index 000000000000..d3137d506e02
--- /dev/null
+++ 
b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedSimpleFunctionRepository.java
@@ -0,0 +1,50 @@
+/*
+ * 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.mbean;
+
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.api.management.ManagedResource;
+import 
org.apache.camel.api.management.mbean.ManagedSimpleFunctionRegistryMBean;
+import org.apache.camel.spi.SimpleFunctionRegistry;
+
+@ManagedResource(description = "Managed SimpleFunctionRegistry")
+public class ManagedSimpleFunctionRepository extends ManagedService implements 
ManagedSimpleFunctionRegistryMBean {
+
+    private final SimpleFunctionRegistry registry;
+
+    public ManagedSimpleFunctionRepository(CamelContext context, 
SimpleFunctionRegistry simpleFunctionRegistry) {
+        super(context, simpleFunctionRegistry);
+        this.registry = simpleFunctionRegistry;
+    }
+
+    @Override
+    public int getSize() {
+        return registry.size();
+    }
+
+    @Override
+    public Set<String> getFunctionNames() {
+        return registry.getFunctionNames();
+    }
+
+    @Override
+    public boolean hasFunction(String name) {
+        return registry.getFunction(name) != null;
+    }
+}
diff --git 
a/core/camel-management/src/test/java/org/apache/camel/management/ManagedSimpleFunctionRegistryTest.java
 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedSimpleFunctionRegistryTest.java
new file mode 100644
index 000000000000..93ac38180fe4
--- /dev/null
+++ 
b/core/camel-management/src/test/java/org/apache/camel/management/ManagedSimpleFunctionRegistryTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.Set;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.SimpleFunctionRegistry;
+import org.apache.camel.support.PluginHelper;
+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_SERVICE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@DisabledOnOs(OS.AIX)
+public class ManagedSimpleFunctionRegistryTest extends ManagementTestSupport {
+
+    @Test
+    public void testSimpleFunction() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bonjour World");
+
+        template.sendBody("direct:start", "World");
+
+        assertMockEndpointsSatisfied();
+
+        MBeanServer mbeanServer = getMBeanServer();
+        ObjectName name = getCamelObjectName(TYPE_SERVICE, 
"DefaultSimpleFunctionRegistry");
+
+        Integer size = (Integer) mbeanServer.getAttribute(name, "Size");
+        assertEquals(1, size);
+
+        Set<String> names = (Set) mbeanServer.getAttribute(name, 
"FunctionNames");
+        assertEquals(1, names.size());
+        assertEquals("hi", names.iterator().next());
+
+        Boolean bool
+                = (Boolean) mbeanServer.invoke(name, "hasFunction", new 
Object[] { "hi" }, new String[] { "java.lang.String" });
+        assertEquals(Boolean.TRUE, bool);
+
+        bool = (Boolean) mbeanServer.invoke(name, "hasFunction", new Object[] 
{ "goodbye" },
+                new String[] { "java.lang.String" });
+        assertEquals(Boolean.FALSE, bool);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                SimpleFunctionRegistry r = 
PluginHelper.getSimpleFunctionRegistry(context);
+                r.addFunction("hi", simple("Bonjour ${body}"));
+
+                
from("direct:start").setBody(simple("${hi}")).to("mock:result");
+            }
+        };
+    }
+
+}

Reply via email to