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"); + } + }; + } + +}
