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 1e65cbf8278 CAMEL-20970: camel-main - Allow to configure MainListener via applica… (#14790) 1e65cbf8278 is described below commit 1e65cbf8278df1d82dd963baaaaf66411aa14f1e Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu Jul 11 14:56:16 2024 +0200 CAMEL-20970: camel-main - Allow to configure MainListener via applica… (#14790) * CAMEL-20970: camel-main - Allow to configure MainListener via application.properties --- .../main/camel-main-configuration-metadata.json | 2 + .../MainConfigurationPropertiesConfigurer.java | 14 +++ .../camel-main-configuration-metadata.json | 2 + core/camel-main/src/main/docs/main.adoc | 4 +- .../org/apache/camel/main/BaseMainSupport.java | 17 ++++ .../camel/main/MainConfigurationProperties.java | 101 +++++++++++++++++++++ .../org/apache/camel/main/MainListenerTest.java | 17 ++++ .../java/org/apache/camel/main/MyMainListener.java | 29 ++++++ 8 files changed, 185 insertions(+), 1 deletion(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json index 73d756eee1e..48e0cb42495 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json @@ -79,6 +79,8 @@ { "name": "camel.main.logDebugMaxChars", "description": "Is used to limit the maximum length of the logging Camel message bodies. If the message body is longer than the limit, the log message is clipped. Use -1 to have unlimited length. Use for example 1000 to log at most 1000 characters.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int" }, { "name": "camel.main.logExhaustedMessageBody", "description": "Sets whether to log exhausted message body with message history. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.logMask", "description": "Sets whether log mask is enabled or not. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, + { "name": "camel.main.mainListenerClasses", "description": "Sets classes names that will be used for MainListener that makes it possible to do custom logic during starting and stopping camel-main.", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.main.mainListeners", "description": "Sets main listener objects that will be used for MainListener that makes it possible to do custom logic during starting and stopping camel-main.", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "object", "javaType": "java.util.List" }, { "name": "camel.main.mdcLoggingKeysPattern", "description": "Sets the pattern used for determine which custom MDC keys to propagate during message routing when the routing engine continues routing asynchronously for the given message. Setting this pattern to will propagate all custom keys. Or setting the pattern to foo,bar will propagate any keys starting with either foo or bar. Notice that a set of standard Camel MDC keys are always propagated which starts with camel. as key name. [...] { "name": "camel.main.messageHistory", "description": "Sets whether message history is enabled or not. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.modeline", "description": "Whether camel-k style modeline is also enabled when not using camel-k. Enabling this allows to use a camel-k like experience by being able to configure various settings using modeline directly in your route source code.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java index 6e598b2a464..28b63284bca 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/MainConfigurationPropertiesConfigurer.java @@ -140,6 +140,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "logExhaustedMessageBody": target.setLogExhaustedMessageBody(property(camelContext, boolean.class, value)); return true; case "logmask": case "logMask": target.setLogMask(property(camelContext, boolean.class, value)); return true; + case "mainlistenerclasses": + case "mainListenerClasses": target.setMainListenerClasses(property(camelContext, java.lang.String.class, value)); return true; + case "mainlisteners": + case "mainListeners": target.setMainListeners(property(camelContext, java.util.List.class, value)); return true; case "mdcloggingkeyspattern": case "mdcLoggingKeysPattern": target.setMdcLoggingKeysPattern(property(camelContext, java.lang.String.class, value)); return true; case "messagehistory": @@ -374,6 +378,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "logExhaustedMessageBody": return boolean.class; case "logmask": case "logMask": return boolean.class; + case "mainlistenerclasses": + case "mainListenerClasses": return java.lang.String.class; + case "mainlisteners": + case "mainListeners": return java.util.List.class; case "mdcloggingkeyspattern": case "mdcLoggingKeysPattern": return java.lang.String.class; case "messagehistory": @@ -609,6 +617,10 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "logExhaustedMessageBody": return target.isLogExhaustedMessageBody(); case "logmask": case "logMask": return target.isLogMask(); + case "mainlistenerclasses": + case "mainListenerClasses": return target.getMainListenerClasses(); + case "mainlisteners": + case "mainListeners": return target.getMainListeners(); case "mdcloggingkeyspattern": case "mdcLoggingKeysPattern": return target.getMdcLoggingKeysPattern(); case "messagehistory": @@ -729,6 +741,8 @@ public class MainConfigurationPropertiesConfigurer extends org.apache.camel.supp case "configurations": return org.apache.camel.CamelConfiguration.class; case "globaloptions": case "globalOptions": return java.lang.String.class; + case "mainlisteners": + case "mainListeners": return org.apache.camel.main.MainListener.class; case "routesbuilders": case "routesBuilders": return org.apache.camel.RoutesBuilder.class; default: return null; diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index 73d756eee1e..48e0cb42495 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -79,6 +79,8 @@ { "name": "camel.main.logDebugMaxChars", "description": "Is used to limit the maximum length of the logging Camel message bodies. If the message body is longer than the limit, the log message is clipped. Use -1 to have unlimited length. Use for example 1000 to log at most 1000 characters.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "integer", "javaType": "int" }, { "name": "camel.main.logExhaustedMessageBody", "description": "Sets whether to log exhausted message body with message history. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.logMask", "description": "Sets whether log mask is enabled or not. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, + { "name": "camel.main.mainListenerClasses", "description": "Sets classes names that will be used for MainListener that makes it possible to do custom logic during starting and stopping camel-main.", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "string", "javaType": "java.lang.String" }, + { "name": "camel.main.mainListeners", "description": "Sets main listener objects that will be used for MainListener that makes it possible to do custom logic during starting and stopping camel-main.", "sourceType": "org.apache.camel.main.MainConfigurationProperties", "type": "object", "javaType": "java.util.List" }, { "name": "camel.main.mdcLoggingKeysPattern", "description": "Sets the pattern used for determine which custom MDC keys to propagate during message routing when the routing engine continues routing asynchronously for the given message. Setting this pattern to will propagate all custom keys. Or setting the pattern to foo,bar will propagate any keys starting with either foo or bar. Notice that a set of standard Camel MDC keys are always propagated which starts with camel. as key name. [...] { "name": "camel.main.messageHistory", "description": "Sets whether message history is enabled or not. Default is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, { "name": "camel.main.modeline", "description": "Whether camel-k style modeline is also enabled when not using camel-k. Enabling this allows to use a camel-k like experience by being able to configure various settings using modeline directly in your route source code.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean", "defaultValue": "false" }, diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index 47828c66429..fa04d822266 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -19,7 +19,7 @@ The following tables lists all the options: // main options: START === Camel Main configurations -The camel.main supports 117 options, which are listed below. +The camel.main supports 119 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== @@ -84,6 +84,8 @@ The camel.main supports 117 options, which are listed below. | *camel.main.logDebugMaxChars* | Is used to limit the maximum length of the logging Camel message bodies. If the message body is longer than the limit, the log message is clipped. Use -1 to have unlimited length. Use for example 1000 to log at most 1000 characters. | | int | *camel.main.logExhaustedMessage{zwsp}Body* | Sets whether to log exhausted message body with message history. Default is false. | false | boolean | *camel.main.logMask* | Sets whether log mask is enabled or not. Default is false. | false | boolean +| *camel.main.mainListenerClasses* | Sets classes names that will be used for MainListener that makes it possible to do custom logic during starting and stopping camel-main. | | String +| *camel.main.mainListeners* | Sets main listener objects that will be used for MainListener that makes it possible to do custom logic during starting and stopping camel-main. | | List | *camel.main.mdcLoggingKeys{zwsp}Pattern* | Sets the pattern used for determine which custom MDC keys to propagate during message routing when the routing engine continues routing asynchronously for the given message. Setting this pattern to will propagate all custom keys. Or setting the pattern to foo,bar will propagate any keys starting with either foo or bar. Notice that a set of standard Camel MDC keys are always propagated which starts with camel. as key name. The match rules are a [...] | *camel.main.messageHistory* | Sets whether message history is enabled or not. Default is false. | false | boolean | *camel.main.modeline* | Whether camel-k style modeline is also enabled when not using camel-k. Enabling this allows to use a camel-k like experience by being able to configure various settings using modeline directly in your route source code. | false | boolean diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java index 8ef5d715da3..fb8c24bfeaf 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java @@ -586,6 +586,21 @@ public abstract class BaseMainSupport extends BaseService { } } + protected void configureMainListener(CamelContext camelContext) throws Exception { + // any custom listener in registry + camelContext.getRegistry().findByType(MainListener.class).forEach(this::addMainListener); + // listener from configuration + mainConfigurationProperties.getMainListeners().forEach(this::addMainListener); + if (mainConfigurationProperties.getMainListenerClasses() != null) { + for (String fqn : mainConfigurationProperties.getMainListenerClasses().split(",")) { + fqn = fqn.trim(); + Class<? extends MainListener> clazz + = camelContext.getClassResolver().resolveMandatoryClass(fqn, MainListener.class); + addMainListener(camelContext.getInjector().newInstance(clazz)); + } + } + } + protected void configureRoutesLoader(CamelContext camelContext) { // use main based routes loader ExtendedCamelContext ecc = camelContext.getCamelContextExtension(); @@ -668,6 +683,8 @@ public abstract class BaseMainSupport extends BaseService { configurePackageScan(camelContext); // configure to use our main routes loader configureRoutesLoader(camelContext); + // configure custom main listeners + configureMainListener(camelContext); // ensure camel context is build camelContext.build(); diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java index bd66aff9e1b..e3cf452be1d 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java @@ -47,11 +47,13 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties< private String basePackageScan; private boolean basePackageScanEnabled = true; + private String mainListenerClasses; private String routesBuilderClasses; private String configurationClasses; private List<RoutesBuilder> routesBuilders = new ArrayList<>(); private List<CamelConfiguration> configurations = new ArrayList<>(); + private List<MainListener> mainListeners = new ArrayList<>(); // extended configuration private HealthConfigurationProperties healthConfigurationProperties; @@ -135,6 +137,10 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties< configurations.clear(); configurations = null; } + if (mainListeners != null) { + mainListeners.clear(); + mainListeners = null; + } } // extended @@ -536,6 +542,64 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties< this.extraShutdownTimeout = extraShutdownTimeout; } + // getter and setters - main listener + // -------------------------------------------------------------- + + public String getMainListenerClasses() { + return mainListenerClasses; + } + + /** + * Sets classes names that will be used for {@link MainListener} that makes it possible to do custom logic during + * starting and stopping camel-main. + */ + public void setMainListenerClasses(String mainListenerClasses) { + this.mainListenerClasses = mainListenerClasses; + } + + /** + * Adds {@link MainListener} object to the known list of main listener classes. + */ + @SuppressWarnings("unchecked") + private void addMainListenerClass(Class<? extends MainListener>... listener) { + StringJoiner existing = new StringJoiner(","); + if (mainListenerClasses != null && !mainListenerClasses.isEmpty()) { + existing.add(mainListenerClasses); + } + if (listener != null) { + for (Class<? extends MainListener> clazz : listener) { + existing.add(clazz.getName()); + } + } + setMainListenerClasses(existing.toString()); + } + + /** + * Adds main listener object to the known list of listener objects. + */ + public void addMainListener(MainListener listener) { + mainListeners.add(listener); + } + + /** + * Adds main listener class to the known list of listener objects. + */ + public void addMainListener(Class<? extends MainListener> listener) { + addMainListenerClass(listener); + } + + public List<MainListener> getMainListeners() { + return mainListeners; + } + + /** + * Sets main listener objects that will be used for {@link MainListener} that makes it possible to do custom logic + * during starting and stopping camel-main. + */ + public void setMainListeners(List<MainListener> mainListeners) { + this.mainListeners = mainListeners; + } + // getter and setters - configurations // -------------------------------------------------------------- @@ -779,6 +843,43 @@ public class MainConfigurationProperties extends DefaultConfigurationProperties< return this; } + // fluent builders - main listener + // -------------------------------------------------------------- + + /** + * Sets classes names that will be used for {@link MainListener} that makes it possible to do custom logic during + * starting and stopping camel-main. + */ + public MainConfigurationProperties withMainListeners(String listeners) { + if (this.mainListenerClasses == null) { + this.mainListenerClasses = ""; + } + if (this.mainListenerClasses.isEmpty()) { + this.mainListenerClasses = listeners; + } else { + this.mainListenerClasses = "," + listeners; + } + return this; + } + + /** + * Adds main listener object to the known list of listener objects. + */ + @SuppressWarnings("unchecked") + public MainConfigurationProperties withMainListeners( + Class<? extends MainListener>... listeners) { + addMainListenerClass(listeners); + return this; + } + + /** + * Adds main listener object to the known list of listener objects. + */ + public MainConfigurationProperties withMainListeners(List<MainListener> listeners) { + setMainListeners(listeners); + return this; + } + // fluent builders - configurations // -------------------------------------------------------------- diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainListenerTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainListenerTest.java index 36b6e2142b7..15e903d7abd 100644 --- a/core/camel-main/src/test/java/org/apache/camel/main/MainListenerTest.java +++ b/core/camel-main/src/test/java/org/apache/camel/main/MainListenerTest.java @@ -76,4 +76,21 @@ public class MainListenerTest { main.stop(); } } + + @Test + public void testCustomListener() { + Main main = new Main(); + try { + main.configure().withMainListeners("org.apache.camel.main.MyMainListener"); + main.setDefaultPropertyPlaceholderLocation("false"); + main.setInitialProperties(propertiesOf( + "camel.context.name", "my-ctx")); + main.start(); + + assertEquals("my-special-override", main.getCamelContext().getName()); + } finally { + main.stop(); + } + } + } diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MyMainListener.java b/core/camel-main/src/test/java/org/apache/camel/main/MyMainListener.java new file mode 100644 index 00000000000..c405f7b37ce --- /dev/null +++ b/core/camel-main/src/test/java/org/apache/camel/main/MyMainListener.java @@ -0,0 +1,29 @@ +/* + * 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.main; + +import static org.apache.camel.util.CollectionHelper.propertiesOf; + +public class MyMainListener extends MainListenerSupport { + + @Override + public void beforeConfigure(BaseMainSupport main) { + main.getCamelContext().getPropertiesComponent().setOverrideProperties(propertiesOf( + "camel.context.name", "my-special-override")); + } + +}