diff --git a/core/camel-java-io/pom.xml b/core/camel-java-io/pom.xml index e3d6475c55934..cca24faebf145 100644 --- a/core/camel-java-io/pom.xml +++ b/core/camel-java-io/pom.xml @@ -49,6 +49,17 @@ camel-xml-io test + + + org.apache.camel + camel-core-languages + test + + + org.apache.camel + camel-direct + test + org.junit.jupiter junit-jupiter diff --git a/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java b/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java index 1df84eea2a3be..8ad31bfe061b6 100644 --- a/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java +++ b/core/camel-java-io/src/generated/java/org/apache/camel/java/out/JavaDslModelWriter.java @@ -1958,15 +1958,15 @@ protected void doWriteExpressionSubElementDefinition(StringBuilder sb, Expressio protected void doWriteFaultToleranceConfigurationCommonAttributes(StringBuilder sb, FaultToleranceConfigurationCommon def) { doWriteIdentifiedTypeAttributes(sb, def); doWriteAttribute(sb, "typedGuard", def.getTypedGuard(), null); - doWriteAttribute(sb, "delay", def.getDelay(), "5000"); - doWriteAttribute(sb, "successThreshold", def.getSuccessThreshold(), "1"); - doWriteAttribute(sb, "requestVolumeThreshold", def.getRequestVolumeThreshold(), "20"); - doWriteAttribute(sb, "failureRatio", def.getFailureRatio(), "50"); - doWriteAttribute(sb, "timeoutEnabled", def.getTimeoutEnabled(), "false"); - doWriteAttribute(sb, "timeoutDuration", def.getTimeoutDuration(), "1000"); - doWriteAttribute(sb, "bulkheadEnabled", def.getBulkheadEnabled(), "false"); - doWriteAttribute(sb, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "10"); - doWriteAttribute(sb, "bulkheadWaitingTaskQueue", def.getBulkheadWaitingTaskQueue(), "10"); + doWriteAttribute(sb, "delay", def.getDelay(), null); + doWriteAttribute(sb, "successThreshold", def.getSuccessThreshold(), null); + doWriteAttribute(sb, "requestVolumeThreshold", def.getRequestVolumeThreshold(), null); + doWriteAttribute(sb, "failureRatio", def.getFailureRatio(), null); + doWriteAttribute(sb, "timeoutEnabled", def.getTimeoutEnabled(), null); + doWriteAttribute(sb, "timeoutDuration", def.getTimeoutDuration(), null); + doWriteAttribute(sb, "bulkheadEnabled", def.getBulkheadEnabled(), null); + doWriteAttribute(sb, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), null); + doWriteAttribute(sb, "bulkheadWaitingTaskQueue", def.getBulkheadWaitingTaskQueue(), null); doWriteAttribute(sb, "threadOffloadExecutorService", def.getThreadOffloadExecutorService(), null); } protected void doWriteFaultToleranceConfigurationCommon(StringBuilder sb, FaultToleranceConfigurationCommon def) { @@ -2307,28 +2307,28 @@ protected void doWriteRecipientListDefinition(StringBuilder sb, RecipientListDef protected void doWriteRedeliveryPolicyDefinition(StringBuilder sb, RedeliveryPolicyDefinition def) { doWriteIdentifiedTypeAttributes(sb, def); doWriteAttribute(sb, "maximumRedeliveries", def.getMaximumRedeliveries(), null); - doWriteAttribute(sb, "redeliveryDelay", def.getRedeliveryDelay(), "1000"); + doWriteAttribute(sb, "redeliveryDelay", def.getRedeliveryDelay(), null); doWriteAttribute(sb, "asyncDelayedRedelivery", def.getAsyncDelayedRedelivery(), null); - doWriteAttribute(sb, "backOffMultiplier", def.getBackOffMultiplier(), "2.0"); + doWriteAttribute(sb, "backOffMultiplier", def.getBackOffMultiplier(), null); doWriteAttribute(sb, "useExponentialBackOff", def.getUseExponentialBackOff(), null); - doWriteAttribute(sb, "collisionAvoidanceFactor", def.getCollisionAvoidanceFactor(), "0.15"); + doWriteAttribute(sb, "collisionAvoidanceFactor", def.getCollisionAvoidanceFactor(), null); doWriteAttribute(sb, "useCollisionAvoidance", def.getUseCollisionAvoidance(), null); - doWriteAttribute(sb, "maximumRedeliveryDelay", def.getMaximumRedeliveryDelay(), "60000"); - doWriteAttribute(sb, "retriesExhaustedLogLevel", def.getRetriesExhaustedLogLevel(), "ERROR"); - doWriteAttribute(sb, "retryAttemptedLogLevel", def.getRetryAttemptedLogLevel(), "DEBUG"); - doWriteAttribute(sb, "retryAttemptedLogInterval", def.getRetryAttemptedLogInterval(), "1"); - doWriteAttribute(sb, "logRetryAttempted", def.getLogRetryAttempted(), "true"); - doWriteAttribute(sb, "logStackTrace", def.getLogStackTrace(), "true"); + doWriteAttribute(sb, "maximumRedeliveryDelay", def.getMaximumRedeliveryDelay(), null); + doWriteAttribute(sb, "retriesExhaustedLogLevel", def.getRetriesExhaustedLogLevel(), null); + doWriteAttribute(sb, "retryAttemptedLogLevel", def.getRetryAttemptedLogLevel(), null); + doWriteAttribute(sb, "retryAttemptedLogInterval", def.getRetryAttemptedLogInterval(), null); + doWriteAttribute(sb, "logRetryAttempted", def.getLogRetryAttempted(), null); + doWriteAttribute(sb, "logStackTrace", def.getLogStackTrace(), null); doWriteAttribute(sb, "logRetryStackTrace", def.getLogRetryStackTrace(), null); doWriteAttribute(sb, "logHandled", def.getLogHandled(), null); - doWriteAttribute(sb, "logNewException", def.getLogNewException(), "true"); + doWriteAttribute(sb, "logNewException", def.getLogNewException(), null); doWriteAttribute(sb, "logContinued", def.getLogContinued(), null); - doWriteAttribute(sb, "logExhausted", def.getLogExhausted(), "true"); + doWriteAttribute(sb, "logExhausted", def.getLogExhausted(), null); doWriteAttribute(sb, "logExhaustedMessageHistory", def.getLogExhaustedMessageHistory(), null); doWriteAttribute(sb, "logExhaustedMessageBody", def.getLogExhaustedMessageBody(), null); doWriteAttribute(sb, "disableRedelivery", def.getDisableRedelivery(), null); doWriteAttribute(sb, "delayPattern", def.getDelayPattern(), null); - doWriteAttribute(sb, "allowRedeliveryWhileStopping", def.getAllowRedeliveryWhileStopping(), "true"); + doWriteAttribute(sb, "allowRedeliveryWhileStopping", def.getAllowRedeliveryWhileStopping(), null); doWriteAttribute(sb, "exchangeFormatterRef", def.getExchangeFormatterRef(), null); } protected void doWriteRemoveHeaderDefinition(StringBuilder sb, RemoveHeaderDefinition def) { @@ -2368,29 +2368,29 @@ protected void doWriteResilience4jConfigurationCommonAttributes(StringBuilder sb doWriteIdentifiedTypeAttributes(sb, def); doWriteAttribute(sb, "circuitBreaker", def.getCircuitBreaker(), null); doWriteAttribute(sb, "config", def.getConfig(), null); - doWriteAttribute(sb, "failureRateThreshold", def.getFailureRateThreshold(), "50"); - doWriteAttribute(sb, "permittedNumberOfCallsInHalfOpenState", def.getPermittedNumberOfCallsInHalfOpenState(), "10"); - doWriteAttribute(sb, "throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), "false"); - doWriteAttribute(sb, "slidingWindowSize", def.getSlidingWindowSize(), "100"); - doWriteAttribute(sb, "slidingWindowType", def.getSlidingWindowType(), "COUNT_BASED"); - doWriteAttribute(sb, "slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), "SYNCHRONIZED"); - doWriteAttribute(sb, "minimumNumberOfCalls", def.getMinimumNumberOfCalls(), "100"); - doWriteAttribute(sb, "writableStackTraceEnabled", def.getWritableStackTraceEnabled(), "true"); - doWriteAttribute(sb, "waitDurationInOpenState", def.getWaitDurationInOpenState(), "60000"); - doWriteAttribute(sb, "automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), "false"); - doWriteAttribute(sb, "maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), "0"); - doWriteAttribute(sb, "slowCallRateThreshold", def.getSlowCallRateThreshold(), "100"); - doWriteAttribute(sb, "slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60000"); - doWriteAttribute(sb, "bulkheadEnabled", def.getBulkheadEnabled(), "false"); - doWriteAttribute(sb, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "25"); - doWriteAttribute(sb, "bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), "0"); - doWriteAttribute(sb, "bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), "true"); - doWriteAttribute(sb, "asynchronous", def.getAsynchronous(), "false"); - doWriteAttribute(sb, "timeoutEnabled", def.getTimeoutEnabled(), "false"); + doWriteAttribute(sb, "failureRateThreshold", def.getFailureRateThreshold(), null); + doWriteAttribute(sb, "permittedNumberOfCallsInHalfOpenState", def.getPermittedNumberOfCallsInHalfOpenState(), null); + doWriteAttribute(sb, "throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), null); + doWriteAttribute(sb, "slidingWindowSize", def.getSlidingWindowSize(), null); + doWriteAttribute(sb, "slidingWindowType", def.getSlidingWindowType(), null); + doWriteAttribute(sb, "slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), null); + doWriteAttribute(sb, "minimumNumberOfCalls", def.getMinimumNumberOfCalls(), null); + doWriteAttribute(sb, "writableStackTraceEnabled", def.getWritableStackTraceEnabled(), null); + doWriteAttribute(sb, "waitDurationInOpenState", def.getWaitDurationInOpenState(), null); + doWriteAttribute(sb, "automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), null); + doWriteAttribute(sb, "maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), null); + doWriteAttribute(sb, "slowCallRateThreshold", def.getSlowCallRateThreshold(), null); + doWriteAttribute(sb, "slowCallDurationThreshold", def.getSlowCallDurationThreshold(), null); + doWriteAttribute(sb, "bulkheadEnabled", def.getBulkheadEnabled(), null); + doWriteAttribute(sb, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), null); + doWriteAttribute(sb, "bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), null); + doWriteAttribute(sb, "bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), null); + doWriteAttribute(sb, "asynchronous", def.getAsynchronous(), null); + doWriteAttribute(sb, "timeoutEnabled", def.getTimeoutEnabled(), null); doWriteAttribute(sb, "timeoutExecutorService", def.getTimeoutExecutorService(), null); - doWriteAttribute(sb, "timeoutDuration", def.getTimeoutDuration(), "1000"); - doWriteAttribute(sb, "timeoutCancelRunningFuture", def.getTimeoutCancelRunningFuture(), "true"); - doWriteAttribute(sb, "micrometerEnabled", def.getMicrometerEnabled(), "false"); + doWriteAttribute(sb, "timeoutDuration", def.getTimeoutDuration(), null); + doWriteAttribute(sb, "timeoutCancelRunningFuture", def.getTimeoutCancelRunningFuture(), null); + doWriteAttribute(sb, "micrometerEnabled", def.getMicrometerEnabled(), null); } protected void doWriteResilience4jConfigurationCommonElements(StringBuilder sb, Resilience4jConfigurationCommon def) { doWriteStringList(sb, null, "ignoreException", def.getIgnoreExceptions()); @@ -2457,8 +2457,8 @@ protected void doWriteRouteDefinition(StringBuilder sb, RouteDefinition def) { doWriteAttribute(sb, "delayer", def.getDelayer(), null); doWriteAttribute(sb, "errorHandlerRef", def.getErrorHandlerRef(), null); doWriteAttribute(sb, "routePolicyRef", def.getRoutePolicyRef(), null); - doWriteAttribute(sb, "shutdownRoute", def.getShutdownRoute(), "Default"); - doWriteAttribute(sb, "shutdownRunningTask", def.getShutdownRunningTask(), "CompleteCurrentTaskOnly"); + doWriteAttribute(sb, "shutdownRoute", def.getShutdownRoute(), null); + doWriteAttribute(sb, "shutdownRunningTask", def.getShutdownRunningTask(), null); doWriteAttribute(sb, "precondition", def.getPrecondition(), null); doWriteChildList(sb, "routeProperty", def.getRouteProperties(), this::doWritePropertyDefinition); doWriteChildElement(sb, "errorHandler", def.getErrorHandler(), this::doWriteErrorHandlerDefinition); @@ -3825,14 +3825,14 @@ protected void doWriteRestBindingDefinition(StringBuilder sb, RestBindingDefinit doWriteOptionalIdentifiedDefinitionAttributes(sb, def); doWriteAttribute(sb, "consumes", def.getConsumes(), null); doWriteAttribute(sb, "produces", def.getProduces(), null); - doWriteAttribute(sb, "bindingMode", def.getBindingMode(), "off"); + doWriteAttribute(sb, "bindingMode", def.getBindingMode(), null); doWriteAttribute(sb, "type", def.getType(), null); doWriteAttribute(sb, "outType", def.getOutType(), null); - doWriteAttribute(sb, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute(sb, "clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute(sb, "clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute(sb, "enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute(sb, "enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute(sb, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute(sb, "clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute(sb, "clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute(sb, "enableCORS", def.getEnableCORS(), null); + doWriteAttribute(sb, "enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute(sb, "component", def.getComponent(), null); } protected void doWriteRestConfigurationDefinition(StringBuilder sb, RestConfigurationDefinition def) { @@ -3850,13 +3850,13 @@ protected void doWriteRestConfigurationDefinition(StringBuilder sb, RestConfigur doWriteAttribute(sb, "apiContextRouteId", def.getApiContextRouteId(), null); doWriteAttribute(sb, "apiVendorExtension", def.getApiVendorExtension(), "false"); doWriteAttribute(sb, "hostNameResolver", toString(def.getHostNameResolver()), "allLocalIp"); - doWriteAttribute(sb, "bindingMode", toString(def.getBindingMode()), "off"); + doWriteAttribute(sb, "bindingMode", toString(def.getBindingMode()), null); doWriteAttribute(sb, "bindingPackageScan", def.getBindingPackageScan(), null); - doWriteAttribute(sb, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute(sb, "clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute(sb, "clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute(sb, "enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute(sb, "enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute(sb, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute(sb, "clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute(sb, "clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute(sb, "enableCORS", def.getEnableCORS(), null); + doWriteAttribute(sb, "enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute(sb, "inlineRoutes", def.getInlineRoutes(), "true"); doWriteAttribute(sb, "jsonDataFormat", def.getJsonDataFormat(), "jackson"); doWriteAttribute(sb, "xmlDataFormat", def.getXmlDataFormat(), "jaxb"); @@ -3874,12 +3874,12 @@ protected void doWriteRestDefinition(StringBuilder sb, RestDefinition def) { doWriteAttribute(sb, "path", def.getPath(), null); doWriteAttribute(sb, "consumes", def.getConsumes(), null); doWriteAttribute(sb, "produces", def.getProduces(), null); - doWriteAttribute(sb, "bindingMode", def.getBindingMode(), "off"); - doWriteAttribute(sb, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute(sb, "clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute(sb, "clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute(sb, "enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute(sb, "enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute(sb, "bindingMode", def.getBindingMode(), null); + doWriteAttribute(sb, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute(sb, "clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute(sb, "clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute(sb, "enableCORS", def.getEnableCORS(), null); + doWriteAttribute(sb, "enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute(sb, "apiDocs", def.getApiDocs(), "true"); doWriteAttribute(sb, "tag", def.getTag(), null); doWriteChildList(sb, "verbs", def.getVerbs(), this::doWriteVerbDefinitionRef); @@ -3922,19 +3922,19 @@ protected void doWriteSecurityDefinition(StringBuilder sb, SecurityDefinition de } protected void doWriteVerbDefinitionAttributes(StringBuilder sb, VerbDefinition def) { doWriteOptionalIdentifiedDefinitionAttributes(sb, def); - doWriteAttribute(sb, "enableCORS", def.getEnableCORS(), "false"); + doWriteAttribute(sb, "enableCORS", def.getEnableCORS(), null); doWriteAttribute(sb, "deprecated", def.getDeprecated(), "false"); doWriteAttribute(sb, "streamCache", def.getStreamCache(), null); doWriteAttribute(sb, "type", def.getType(), null); doWriteAttribute(sb, "outType", def.getOutType(), null); - doWriteAttribute(sb, "clientResponseValidation", def.getClientResponseValidation(), "false"); + doWriteAttribute(sb, "clientResponseValidation", def.getClientResponseValidation(), null); doWriteAttribute(sb, "path", def.getPath(), null); doWriteAttribute(sb, "routeId", def.getRouteId(), null); - doWriteAttribute(sb, "bindingMode", def.getBindingMode(), "off"); + doWriteAttribute(sb, "bindingMode", def.getBindingMode(), null); doWriteAttribute(sb, "apiDocs", def.getApiDocs(), "true"); - doWriteAttribute(sb, "enableNoContentResponse", def.getEnableNoContentResponse(), "false"); - doWriteAttribute(sb, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute(sb, "clientRequestValidation", def.getClientRequestValidation(), "false"); + doWriteAttribute(sb, "enableNoContentResponse", def.getEnableNoContentResponse(), null); + doWriteAttribute(sb, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute(sb, "clientRequestValidation", def.getClientRequestValidation(), null); doWriteAttribute(sb, "produces", def.getProduces(), null); doWriteAttribute(sb, "disabled", def.getDisabled(), null); doWriteAttribute(sb, "consumes", def.getConsumes(), null); diff --git a/core/camel-java-io/src/test/java/org/apache/camel/java/JavaDumpExplicitDefaultValuesTest.java b/core/camel-java-io/src/test/java/org/apache/camel/java/JavaDumpExplicitDefaultValuesTest.java new file mode 100644 index 0000000000000..63bd7ccecf440 --- /dev/null +++ b/core/camel-java-io/src/test/java/org/apache/camel/java/JavaDumpExplicitDefaultValuesTest.java @@ -0,0 +1,161 @@ +/* + * 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.java; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.tools.DiagnosticCollector; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +import org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.model.errorhandler.DefaultErrorHandlerDefinition; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * A route that sets an option to its documented default value, where "not set" means "the value of a parent level", + * runs the same once its Java dump is compiled and loaded again. + */ +public class JavaDumpExplicitDefaultValuesTest { + + private static final String CLASS_NAME = "test.generated.DumpedRoutes"; + + @Test + public void onExceptionRedeliveryDelayUnderErrorHandler() throws Exception { + // the onException redelivers after 1000 ms (the documented default), the error handler after 30 s: an option of + // the onException that is not set takes the value of the error handler + RouteBuilder routes = new RouteBuilder() { + @Override + public void configure() { + from("direct:start").routeId("redelivery") + .onException(IllegalStateException.class).maximumRedeliveries(1).redeliveryDelay(1000) + .handled(true).setBody(constant("handled")).end() + .throwException(IllegalStateException.class, "Forced"); + } + }; + + assertThat(run(routes)).isEqualTo("handled"); + + String dumped; + try (DefaultCamelContext context = createContext()) { + context.addRoutes(routes); + dumped = new LwModelToJavaDumper().dumpModelAsJava(context, context.getRouteDefinition("redelivery")); + } + assertThat(run(load(dumped))).as(dumped).isEqualTo("handled"); + } + + private static DefaultCamelContext createContext() { + DefaultCamelContext context = new DefaultCamelContext(); + context.getCamelContextExtension().setErrorHandlerFactory( + new DefaultErrorHandlerDefinition().maximumRedeliveries(3).redeliveryDelay(30000)); + context.getShutdownStrategy().setTimeout(1); + return context; + } + + private static String run(RoutesBuilder routes) throws Exception { + try (DefaultCamelContext context = createContext()) { + context.addRoutes(routes); + context.start(); + return call(context); + } + } + + private static String call(CamelContext context) { + try { + return context.createProducerTemplate().asyncRequestBody("direct:start", "x", String.class) + .get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + return "not redelivered within 10 seconds"; + } catch (Exception e) { + return e.toString(); + } + } + + /** Compiles the dump in a RouteBuilder and creates an instance of it. */ + private static RoutesBuilder load(String dump) throws Exception { + String source = "package test.generated;\n\n" + + "import org.apache.camel.ExchangePattern;\n" + + "import org.apache.camel.LoggingLevel;\n" + + "import org.apache.camel.Predicate;\n" + + "import org.apache.camel.builder.RouteBuilder;\n\n" + + "public class DumpedRoutes extends RouteBuilder {\n" + + " @Override\n" + + " public void configure() throws Exception {\n" + + dump + "\n" + + " }\n" + + "}\n"; + + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + assertThat(compiler).as("a JDK is needed to compile the dump").isNotNull(); + DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + Map classes = new HashMap<>(); + JavaFileManager fileManager + = new ForwardingJavaFileManager<>(compiler.getStandardFileManager(diagnostics, null, null)) { + @Override + public JavaFileObject getJavaFileForOutput( + Location location, String name, JavaFileObject.Kind kind, FileObject sibling) { + return new SimpleJavaFileObject(URI.create("mem:///" + name.replace('.', '/') + kind.extension), kind) { + @Override + public OutputStream openOutputStream() { + return classes.computeIfAbsent(name, n -> new ByteArrayOutputStream()); + } + }; + } + }; + JavaFileObject file = new SimpleJavaFileObject( + URI.create("string:///" + CLASS_NAME.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension), + JavaFileObject.Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + }; + boolean compiled = compiler.getTask(null, fileManager, diagnostics, + List.of("-proc:none", "-classpath", System.getProperty("java.class.path")), null, List.of(file)).call(); + assertThat(compiled).as(diagnostics.getDiagnostics() + "\n" + source).isTrue(); + + ClassLoader loader = new ClassLoader(JavaDumpExplicitDefaultValuesTest.class.getClassLoader()) { + @Override + protected Class findClass(String name) throws ClassNotFoundException { + ByteArrayOutputStream bytes = classes.get(name); + if (bytes == null) { + throw new ClassNotFoundException(name); + } + byte[] b = bytes.toByteArray(); + return defineClass(name, b, 0, b.length); + } + }; + return (RoutesBuilder) loader.loadClass(CLASS_NAME).getDeclaredConstructor().newInstance(); + } +} diff --git a/core/camel-java-io/src/test/java/org/apache/camel/java/LwModelToJavaDumperTest.java b/core/camel-java-io/src/test/java/org/apache/camel/java/LwModelToJavaDumperTest.java index 6e77e7bb614a2..ae4d9a667fa2a 100644 --- a/core/camel-java-io/src/test/java/org/apache/camel/java/LwModelToJavaDumperTest.java +++ b/core/camel-java-io/src/test/java/org/apache/camel/java/LwModelToJavaDumperTest.java @@ -25,6 +25,7 @@ import org.apache.camel.model.RouteConfigurationDefinition; import org.apache.camel.model.RouteTemplateDefinition; import org.apache.camel.model.ThrowExceptionDefinition; +import org.apache.camel.model.rest.RestBindingMode; import org.apache.camel.model.rest.RestDefinition; import org.junit.jupiter.api.Test; @@ -106,4 +107,30 @@ public void configure() { .getExceptionType()).isNull(); } } + + /** + * An option set to its documented default value is written: when it is not set, the option takes the value of a + * parent level (the rest configuration for a verb, the error handler for the redelivery of an onException). + */ + @Test + public void testDumpOptionsSetToTheirDefaultValue() throws Exception { + try (DefaultCamelContext context = new DefaultCamelContext()) { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() { + rest("/api").get("/raw").bindingMode(RestBindingMode.off).to("direct:raw"); + + from("direct:start").routeId("redelivery") + .onException(IllegalStateException.class).maximumRedeliveries(1).redeliveryDelay(1000).end() + .to("mock:result"); + } + }); + Model model = context.getCamelContextExtension().getContextPlugin(Model.class); + LwModelToJavaDumper dumper = new LwModelToJavaDumper(); + + assertThat(dumper.dumpModelAsJava(context, model.getRestDefinitions().get(0))).contains(".bindingMode(\"off\")"); + assertThat(dumper.dumpModelAsJava(context, context.getRouteDefinition("redelivery"))) + .contains(".redeliveryDelay(\"1000\")"); + } + } } diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java index 824c2a5978089..d53218b156d70 100644 --- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java +++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java @@ -1035,15 +1035,15 @@ protected void doWriteExpressionSubElementDefinition(String name, ExpressionSubE protected void doWriteFaultToleranceConfigurationCommonAttributes(FaultToleranceConfigurationCommon def) throws IOException { doWriteIdentifiedTypeAttributes(def); doWriteAttribute("typedGuard", def.getTypedGuard(), null); - doWriteAttribute("delay", def.getDelay(), "5000"); - doWriteAttribute("successThreshold", def.getSuccessThreshold(), "1"); - doWriteAttribute("requestVolumeThreshold", def.getRequestVolumeThreshold(), "20"); - doWriteAttribute("failureRatio", def.getFailureRatio(), "50"); - doWriteAttribute("timeoutEnabled", def.getTimeoutEnabled(), "false"); - doWriteAttribute("timeoutDuration", def.getTimeoutDuration(), "1000"); - doWriteAttribute("bulkheadEnabled", def.getBulkheadEnabled(), "false"); - doWriteAttribute("bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "10"); - doWriteAttribute("bulkheadWaitingTaskQueue", def.getBulkheadWaitingTaskQueue(), "10"); + doWriteAttribute("delay", def.getDelay(), null); + doWriteAttribute("successThreshold", def.getSuccessThreshold(), null); + doWriteAttribute("requestVolumeThreshold", def.getRequestVolumeThreshold(), null); + doWriteAttribute("failureRatio", def.getFailureRatio(), null); + doWriteAttribute("timeoutEnabled", def.getTimeoutEnabled(), null); + doWriteAttribute("timeoutDuration", def.getTimeoutDuration(), null); + doWriteAttribute("bulkheadEnabled", def.getBulkheadEnabled(), null); + doWriteAttribute("bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), null); + doWriteAttribute("bulkheadWaitingTaskQueue", def.getBulkheadWaitingTaskQueue(), null); doWriteAttribute("threadOffloadExecutorService", def.getThreadOffloadExecutorService(), null); } protected void doWriteFaultToleranceConfigurationCommon(String name, FaultToleranceConfigurationCommon def) throws IOException { @@ -1467,28 +1467,28 @@ protected void doWriteRedeliveryPolicyDefinition(String name, RedeliveryPolicyDe startElement(name); doWriteIdentifiedTypeAttributes(def); doWriteAttribute("maximumRedeliveries", def.getMaximumRedeliveries(), null); - doWriteAttribute("redeliveryDelay", def.getRedeliveryDelay(), "1000"); + doWriteAttribute("redeliveryDelay", def.getRedeliveryDelay(), null); doWriteAttribute("asyncDelayedRedelivery", def.getAsyncDelayedRedelivery(), null); - doWriteAttribute("backOffMultiplier", def.getBackOffMultiplier(), "2.0"); + doWriteAttribute("backOffMultiplier", def.getBackOffMultiplier(), null); doWriteAttribute("useExponentialBackOff", def.getUseExponentialBackOff(), null); - doWriteAttribute("collisionAvoidanceFactor", def.getCollisionAvoidanceFactor(), "0.15"); + doWriteAttribute("collisionAvoidanceFactor", def.getCollisionAvoidanceFactor(), null); doWriteAttribute("useCollisionAvoidance", def.getUseCollisionAvoidance(), null); - doWriteAttribute("maximumRedeliveryDelay", def.getMaximumRedeliveryDelay(), "60000"); - doWriteAttribute("retriesExhaustedLogLevel", def.getRetriesExhaustedLogLevel(), "ERROR"); - doWriteAttribute("retryAttemptedLogLevel", def.getRetryAttemptedLogLevel(), "DEBUG"); - doWriteAttribute("retryAttemptedLogInterval", def.getRetryAttemptedLogInterval(), "1"); - doWriteAttribute("logRetryAttempted", def.getLogRetryAttempted(), "true"); - doWriteAttribute("logStackTrace", def.getLogStackTrace(), "true"); + doWriteAttribute("maximumRedeliveryDelay", def.getMaximumRedeliveryDelay(), null); + doWriteAttribute("retriesExhaustedLogLevel", def.getRetriesExhaustedLogLevel(), null); + doWriteAttribute("retryAttemptedLogLevel", def.getRetryAttemptedLogLevel(), null); + doWriteAttribute("retryAttemptedLogInterval", def.getRetryAttemptedLogInterval(), null); + doWriteAttribute("logRetryAttempted", def.getLogRetryAttempted(), null); + doWriteAttribute("logStackTrace", def.getLogStackTrace(), null); doWriteAttribute("logRetryStackTrace", def.getLogRetryStackTrace(), null); doWriteAttribute("logHandled", def.getLogHandled(), null); - doWriteAttribute("logNewException", def.getLogNewException(), "true"); + doWriteAttribute("logNewException", def.getLogNewException(), null); doWriteAttribute("logContinued", def.getLogContinued(), null); - doWriteAttribute("logExhausted", def.getLogExhausted(), "true"); + doWriteAttribute("logExhausted", def.getLogExhausted(), null); doWriteAttribute("logExhaustedMessageHistory", def.getLogExhaustedMessageHistory(), null); doWriteAttribute("logExhaustedMessageBody", def.getLogExhaustedMessageBody(), null); doWriteAttribute("disableRedelivery", def.getDisableRedelivery(), null); doWriteAttribute("delayPattern", def.getDelayPattern(), null); - doWriteAttribute("allowRedeliveryWhileStopping", def.getAllowRedeliveryWhileStopping(), "true"); + doWriteAttribute("allowRedeliveryWhileStopping", def.getAllowRedeliveryWhileStopping(), null); doWriteAttribute("exchangeFormatterRef", def.getExchangeFormatterRef(), null); endElement(name); } @@ -1541,29 +1541,29 @@ protected void doWriteResilience4jConfigurationCommonAttributes(Resilience4jConf doWriteIdentifiedTypeAttributes(def); doWriteAttribute("circuitBreaker", def.getCircuitBreaker(), null); doWriteAttribute("config", def.getConfig(), null); - doWriteAttribute("failureRateThreshold", def.getFailureRateThreshold(), "50"); - doWriteAttribute("permittedNumberOfCallsInHalfOpenState", def.getPermittedNumberOfCallsInHalfOpenState(), "10"); - doWriteAttribute("throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), "false"); - doWriteAttribute("slidingWindowSize", def.getSlidingWindowSize(), "100"); - doWriteAttribute("slidingWindowType", def.getSlidingWindowType(), "COUNT_BASED"); - doWriteAttribute("slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), "SYNCHRONIZED"); - doWriteAttribute("minimumNumberOfCalls", def.getMinimumNumberOfCalls(), "100"); - doWriteAttribute("writableStackTraceEnabled", def.getWritableStackTraceEnabled(), "true"); - doWriteAttribute("waitDurationInOpenState", def.getWaitDurationInOpenState(), "60000"); - doWriteAttribute("automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), "false"); - doWriteAttribute("maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), "0"); - doWriteAttribute("slowCallRateThreshold", def.getSlowCallRateThreshold(), "100"); - doWriteAttribute("slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60000"); - doWriteAttribute("bulkheadEnabled", def.getBulkheadEnabled(), "false"); - doWriteAttribute("bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "25"); - doWriteAttribute("bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), "0"); - doWriteAttribute("bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), "true"); - doWriteAttribute("asynchronous", def.getAsynchronous(), "false"); - doWriteAttribute("timeoutEnabled", def.getTimeoutEnabled(), "false"); + doWriteAttribute("failureRateThreshold", def.getFailureRateThreshold(), null); + doWriteAttribute("permittedNumberOfCallsInHalfOpenState", def.getPermittedNumberOfCallsInHalfOpenState(), null); + doWriteAttribute("throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), null); + doWriteAttribute("slidingWindowSize", def.getSlidingWindowSize(), null); + doWriteAttribute("slidingWindowType", def.getSlidingWindowType(), null); + doWriteAttribute("slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), null); + doWriteAttribute("minimumNumberOfCalls", def.getMinimumNumberOfCalls(), null); + doWriteAttribute("writableStackTraceEnabled", def.getWritableStackTraceEnabled(), null); + doWriteAttribute("waitDurationInOpenState", def.getWaitDurationInOpenState(), null); + doWriteAttribute("automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), null); + doWriteAttribute("maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), null); + doWriteAttribute("slowCallRateThreshold", def.getSlowCallRateThreshold(), null); + doWriteAttribute("slowCallDurationThreshold", def.getSlowCallDurationThreshold(), null); + doWriteAttribute("bulkheadEnabled", def.getBulkheadEnabled(), null); + doWriteAttribute("bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), null); + doWriteAttribute("bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), null); + doWriteAttribute("bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), null); + doWriteAttribute("asynchronous", def.getAsynchronous(), null); + doWriteAttribute("timeoutEnabled", def.getTimeoutEnabled(), null); doWriteAttribute("timeoutExecutorService", def.getTimeoutExecutorService(), null); - doWriteAttribute("timeoutDuration", def.getTimeoutDuration(), "1000"); - doWriteAttribute("timeoutCancelRunningFuture", def.getTimeoutCancelRunningFuture(), "true"); - doWriteAttribute("micrometerEnabled", def.getMicrometerEnabled(), "false"); + doWriteAttribute("timeoutDuration", def.getTimeoutDuration(), null); + doWriteAttribute("timeoutCancelRunningFuture", def.getTimeoutCancelRunningFuture(), null); + doWriteAttribute("micrometerEnabled", def.getMicrometerEnabled(), null); } protected void doWriteResilience4jConfigurationCommonElements(Resilience4jConfigurationCommon def) throws IOException { doWriteList(null, "ignoreException", def.getIgnoreExceptions(), this::doWriteString); @@ -1651,8 +1651,8 @@ protected void doWriteRouteDefinition(String name, RouteDefinition def) throws I doWriteAttribute("delayer", def.getDelayer(), null); doWriteAttribute("errorHandlerRef", def.getErrorHandlerRef(), null); doWriteAttribute("routePolicyRef", def.getRoutePolicyRef(), null); - doWriteAttribute("shutdownRoute", def.getShutdownRoute(), "Default"); - doWriteAttribute("shutdownRunningTask", def.getShutdownRunningTask(), "CompleteCurrentTaskOnly"); + doWriteAttribute("shutdownRoute", def.getShutdownRoute(), null); + doWriteAttribute("shutdownRunningTask", def.getShutdownRunningTask(), null); doWriteAttribute("precondition", def.getPrecondition(), null); doWriteList(null, "routeProperty", def.getRouteProperties(), this::doWritePropertyDefinition); doWriteElement("errorHandler", def.getErrorHandler(), this::doWriteErrorHandlerDefinition); @@ -3357,14 +3357,14 @@ protected void doWriteRestBindingDefinition(String name, RestBindingDefinition d doWriteOptionalIdentifiedDefinitionAttributes(def); doWriteAttribute("consumes", def.getConsumes(), null); doWriteAttribute("produces", def.getProduces(), null); - doWriteAttribute("bindingMode", def.getBindingMode(), "off"); + doWriteAttribute("bindingMode", def.getBindingMode(), null); doWriteAttribute("type", def.getType(), null); doWriteAttribute("outType", def.getOutType(), null); - doWriteAttribute("skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute("clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute("clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute("enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute("enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute("skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute("clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute("clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute("enableCORS", def.getEnableCORS(), null); + doWriteAttribute("enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute("component", def.getComponent(), null); endElement(name); } @@ -3384,13 +3384,13 @@ protected void doWriteRestConfigurationDefinition(String name, RestConfiguration doWriteAttribute("apiContextRouteId", def.getApiContextRouteId(), null); doWriteAttribute("apiVendorExtension", def.getApiVendorExtension(), "false"); doWriteAttribute("hostNameResolver", toString(def.getHostNameResolver()), "allLocalIp"); - doWriteAttribute("bindingMode", toString(def.getBindingMode()), "off"); + doWriteAttribute("bindingMode", toString(def.getBindingMode()), null); doWriteAttribute("bindingPackageScan", def.getBindingPackageScan(), null); - doWriteAttribute("skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute("clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute("clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute("enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute("enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute("skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute("clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute("clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute("enableCORS", def.getEnableCORS(), null); + doWriteAttribute("enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute("inlineRoutes", def.getInlineRoutes(), "true"); doWriteAttribute("jsonDataFormat", def.getJsonDataFormat(), "jackson"); doWriteAttribute("xmlDataFormat", def.getXmlDataFormat(), "jaxb"); @@ -3410,12 +3410,12 @@ protected void doWriteRestDefinition(String name, RestDefinition def) throws IOE doWriteAttribute("path", def.getPath(), null); doWriteAttribute("consumes", def.getConsumes(), null); doWriteAttribute("produces", def.getProduces(), null); - doWriteAttribute("bindingMode", def.getBindingMode(), "off"); - doWriteAttribute("skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute("clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute("clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute("enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute("enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute("bindingMode", def.getBindingMode(), null); + doWriteAttribute("skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute("clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute("clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute("enableCORS", def.getEnableCORS(), null); + doWriteAttribute("enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute("apiDocs", def.getApiDocs(), "true"); doWriteAttribute("tag", def.getTag(), null); doWriteList(null, null, def.getVerbs(), this::doWriteVerbDefinitionRef); @@ -3467,19 +3467,19 @@ protected void doWriteSecurityDefinition(String name, SecurityDefinition def) th } protected void doWriteVerbDefinitionAttributes(VerbDefinition def) throws IOException { doWriteOptionalIdentifiedDefinitionAttributes(def); - doWriteAttribute("enableCORS", def.getEnableCORS(), "false"); + doWriteAttribute("enableCORS", def.getEnableCORS(), null); doWriteAttribute("deprecated", def.getDeprecated(), "false"); doWriteAttribute("streamCache", def.getStreamCache(), null); doWriteAttribute("type", def.getType(), null); doWriteAttribute("outType", def.getOutType(), null); - doWriteAttribute("clientResponseValidation", def.getClientResponseValidation(), "false"); + doWriteAttribute("clientResponseValidation", def.getClientResponseValidation(), null); doWriteAttribute("path", def.getPath(), null); doWriteAttribute("routeId", def.getRouteId(), null); - doWriteAttribute("bindingMode", def.getBindingMode(), "off"); + doWriteAttribute("bindingMode", def.getBindingMode(), null); doWriteAttribute("apiDocs", def.getApiDocs(), "true"); - doWriteAttribute("enableNoContentResponse", def.getEnableNoContentResponse(), "false"); - doWriteAttribute("skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute("clientRequestValidation", def.getClientRequestValidation(), "false"); + doWriteAttribute("enableNoContentResponse", def.getEnableNoContentResponse(), null); + doWriteAttribute("skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute("clientRequestValidation", def.getClientRequestValidation(), null); doWriteAttribute("produces", def.getProduces(), null); doWriteAttribute("disabled", def.getDisabled(), null); doWriteAttribute("consumes", def.getConsumes(), null); diff --git a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java index 7a1096e27a801..0f0e930a66c5d 100644 --- a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java +++ b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/YamlModelWriter.java @@ -1029,15 +1029,15 @@ protected JsonObject doWriteExpressionSubElementDefinition(ExpressionSubElementD protected void doWriteFaultToleranceConfigurationCommonAttributes(JsonObject jo, FaultToleranceConfigurationCommon def) { doWriteIdentifiedTypeAttributes(jo, def); doWriteAttribute(jo, "typedGuard", def.getTypedGuard(), null); - doWriteAttribute(jo, "delay", def.getDelay(), "5000"); - doWriteAttribute(jo, "successThreshold", def.getSuccessThreshold(), "1"); - doWriteAttribute(jo, "requestVolumeThreshold", def.getRequestVolumeThreshold(), "20"); - doWriteAttribute(jo, "failureRatio", def.getFailureRatio(), "50"); - doWriteAttribute(jo, "timeoutEnabled", def.getTimeoutEnabled(), "false"); - doWriteAttribute(jo, "timeoutDuration", def.getTimeoutDuration(), "1000"); - doWriteAttribute(jo, "bulkheadEnabled", def.getBulkheadEnabled(), "false"); - doWriteAttribute(jo, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "10"); - doWriteAttribute(jo, "bulkheadWaitingTaskQueue", def.getBulkheadWaitingTaskQueue(), "10"); + doWriteAttribute(jo, "delay", def.getDelay(), null); + doWriteAttribute(jo, "successThreshold", def.getSuccessThreshold(), null); + doWriteAttribute(jo, "requestVolumeThreshold", def.getRequestVolumeThreshold(), null); + doWriteAttribute(jo, "failureRatio", def.getFailureRatio(), null); + doWriteAttribute(jo, "timeoutEnabled", def.getTimeoutEnabled(), null); + doWriteAttribute(jo, "timeoutDuration", def.getTimeoutDuration(), null); + doWriteAttribute(jo, "bulkheadEnabled", def.getBulkheadEnabled(), null); + doWriteAttribute(jo, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), null); + doWriteAttribute(jo, "bulkheadWaitingTaskQueue", def.getBulkheadWaitingTaskQueue(), null); doWriteAttribute(jo, "threadOffloadExecutorService", def.getThreadOffloadExecutorService(), null); } protected JsonObject doWriteFaultToleranceConfigurationCommon(FaultToleranceConfigurationCommon def) { @@ -1461,28 +1461,28 @@ protected JsonObject doWriteRedeliveryPolicyDefinition(RedeliveryPolicyDefinitio JsonObject jo = new JsonObject(); doWriteIdentifiedTypeAttributes(jo, def); doWriteAttribute(jo, "maximumRedeliveries", def.getMaximumRedeliveries(), null); - doWriteAttribute(jo, "redeliveryDelay", def.getRedeliveryDelay(), "1000"); + doWriteAttribute(jo, "redeliveryDelay", def.getRedeliveryDelay(), null); doWriteAttribute(jo, "asyncDelayedRedelivery", def.getAsyncDelayedRedelivery(), null); - doWriteAttribute(jo, "backOffMultiplier", def.getBackOffMultiplier(), "2.0"); + doWriteAttribute(jo, "backOffMultiplier", def.getBackOffMultiplier(), null); doWriteAttribute(jo, "useExponentialBackOff", def.getUseExponentialBackOff(), null); - doWriteAttribute(jo, "collisionAvoidanceFactor", def.getCollisionAvoidanceFactor(), "0.15"); + doWriteAttribute(jo, "collisionAvoidanceFactor", def.getCollisionAvoidanceFactor(), null); doWriteAttribute(jo, "useCollisionAvoidance", def.getUseCollisionAvoidance(), null); - doWriteAttribute(jo, "maximumRedeliveryDelay", def.getMaximumRedeliveryDelay(), "60000"); - doWriteAttribute(jo, "retriesExhaustedLogLevel", def.getRetriesExhaustedLogLevel(), "ERROR"); - doWriteAttribute(jo, "retryAttemptedLogLevel", def.getRetryAttemptedLogLevel(), "DEBUG"); - doWriteAttribute(jo, "retryAttemptedLogInterval", def.getRetryAttemptedLogInterval(), "1"); - doWriteAttribute(jo, "logRetryAttempted", def.getLogRetryAttempted(), "true"); - doWriteAttribute(jo, "logStackTrace", def.getLogStackTrace(), "true"); + doWriteAttribute(jo, "maximumRedeliveryDelay", def.getMaximumRedeliveryDelay(), null); + doWriteAttribute(jo, "retriesExhaustedLogLevel", def.getRetriesExhaustedLogLevel(), null); + doWriteAttribute(jo, "retryAttemptedLogLevel", def.getRetryAttemptedLogLevel(), null); + doWriteAttribute(jo, "retryAttemptedLogInterval", def.getRetryAttemptedLogInterval(), null); + doWriteAttribute(jo, "logRetryAttempted", def.getLogRetryAttempted(), null); + doWriteAttribute(jo, "logStackTrace", def.getLogStackTrace(), null); doWriteAttribute(jo, "logRetryStackTrace", def.getLogRetryStackTrace(), null); doWriteAttribute(jo, "logHandled", def.getLogHandled(), null); - doWriteAttribute(jo, "logNewException", def.getLogNewException(), "true"); + doWriteAttribute(jo, "logNewException", def.getLogNewException(), null); doWriteAttribute(jo, "logContinued", def.getLogContinued(), null); - doWriteAttribute(jo, "logExhausted", def.getLogExhausted(), "true"); + doWriteAttribute(jo, "logExhausted", def.getLogExhausted(), null); doWriteAttribute(jo, "logExhaustedMessageHistory", def.getLogExhaustedMessageHistory(), null); doWriteAttribute(jo, "logExhaustedMessageBody", def.getLogExhaustedMessageBody(), null); doWriteAttribute(jo, "disableRedelivery", def.getDisableRedelivery(), null); doWriteAttribute(jo, "delayPattern", def.getDelayPattern(), null); - doWriteAttribute(jo, "allowRedeliveryWhileStopping", def.getAllowRedeliveryWhileStopping(), "true"); + doWriteAttribute(jo, "allowRedeliveryWhileStopping", def.getAllowRedeliveryWhileStopping(), null); doWriteAttribute(jo, "exchangeFormatterRef", def.getExchangeFormatterRef(), null); return jo; } @@ -1535,29 +1535,29 @@ protected void doWriteResilience4jConfigurationCommonAttributes(JsonObject jo, R doWriteIdentifiedTypeAttributes(jo, def); doWriteAttribute(jo, "circuitBreaker", def.getCircuitBreaker(), null); doWriteAttribute(jo, "config", def.getConfig(), null); - doWriteAttribute(jo, "failureRateThreshold", def.getFailureRateThreshold(), "50"); - doWriteAttribute(jo, "permittedNumberOfCallsInHalfOpenState", def.getPermittedNumberOfCallsInHalfOpenState(), "10"); - doWriteAttribute(jo, "throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), "false"); - doWriteAttribute(jo, "slidingWindowSize", def.getSlidingWindowSize(), "100"); - doWriteAttribute(jo, "slidingWindowType", def.getSlidingWindowType(), "COUNT_BASED"); - doWriteAttribute(jo, "slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), "SYNCHRONIZED"); - doWriteAttribute(jo, "minimumNumberOfCalls", def.getMinimumNumberOfCalls(), "100"); - doWriteAttribute(jo, "writableStackTraceEnabled", def.getWritableStackTraceEnabled(), "true"); - doWriteAttribute(jo, "waitDurationInOpenState", def.getWaitDurationInOpenState(), "60000"); - doWriteAttribute(jo, "automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), "false"); - doWriteAttribute(jo, "maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), "0"); - doWriteAttribute(jo, "slowCallRateThreshold", def.getSlowCallRateThreshold(), "100"); - doWriteAttribute(jo, "slowCallDurationThreshold", def.getSlowCallDurationThreshold(), "60000"); - doWriteAttribute(jo, "bulkheadEnabled", def.getBulkheadEnabled(), "false"); - doWriteAttribute(jo, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), "25"); - doWriteAttribute(jo, "bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), "0"); - doWriteAttribute(jo, "bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), "true"); - doWriteAttribute(jo, "asynchronous", def.getAsynchronous(), "false"); - doWriteAttribute(jo, "timeoutEnabled", def.getTimeoutEnabled(), "false"); + doWriteAttribute(jo, "failureRateThreshold", def.getFailureRateThreshold(), null); + doWriteAttribute(jo, "permittedNumberOfCallsInHalfOpenState", def.getPermittedNumberOfCallsInHalfOpenState(), null); + doWriteAttribute(jo, "throwExceptionWhenHalfOpenOrOpenState", def.getThrowExceptionWhenHalfOpenOrOpenState(), null); + doWriteAttribute(jo, "slidingWindowSize", def.getSlidingWindowSize(), null); + doWriteAttribute(jo, "slidingWindowType", def.getSlidingWindowType(), null); + doWriteAttribute(jo, "slidingWindowSynchronizationStrategy", def.getSlidingWindowSynchronizationStrategy(), null); + doWriteAttribute(jo, "minimumNumberOfCalls", def.getMinimumNumberOfCalls(), null); + doWriteAttribute(jo, "writableStackTraceEnabled", def.getWritableStackTraceEnabled(), null); + doWriteAttribute(jo, "waitDurationInOpenState", def.getWaitDurationInOpenState(), null); + doWriteAttribute(jo, "automaticTransitionFromOpenToHalfOpenEnabled", def.getAutomaticTransitionFromOpenToHalfOpenEnabled(), null); + doWriteAttribute(jo, "maxWaitDurationInHalfOpenState", def.getMaxWaitDurationInHalfOpenState(), null); + doWriteAttribute(jo, "slowCallRateThreshold", def.getSlowCallRateThreshold(), null); + doWriteAttribute(jo, "slowCallDurationThreshold", def.getSlowCallDurationThreshold(), null); + doWriteAttribute(jo, "bulkheadEnabled", def.getBulkheadEnabled(), null); + doWriteAttribute(jo, "bulkheadMaxConcurrentCalls", def.getBulkheadMaxConcurrentCalls(), null); + doWriteAttribute(jo, "bulkheadMaxWaitDuration", def.getBulkheadMaxWaitDuration(), null); + doWriteAttribute(jo, "bulkheadFairCallHandlingEnabled", def.getBulkheadFairCallHandlingEnabled(), null); + doWriteAttribute(jo, "asynchronous", def.getAsynchronous(), null); + doWriteAttribute(jo, "timeoutEnabled", def.getTimeoutEnabled(), null); doWriteAttribute(jo, "timeoutExecutorService", def.getTimeoutExecutorService(), null); - doWriteAttribute(jo, "timeoutDuration", def.getTimeoutDuration(), "1000"); - doWriteAttribute(jo, "timeoutCancelRunningFuture", def.getTimeoutCancelRunningFuture(), "true"); - doWriteAttribute(jo, "micrometerEnabled", def.getMicrometerEnabled(), "false"); + doWriteAttribute(jo, "timeoutDuration", def.getTimeoutDuration(), null); + doWriteAttribute(jo, "timeoutCancelRunningFuture", def.getTimeoutCancelRunningFuture(), null); + doWriteAttribute(jo, "micrometerEnabled", def.getMicrometerEnabled(), null); } protected void doWriteResilience4jConfigurationCommonElements(JsonObject jo, Resilience4jConfigurationCommon def) { doWriteStringList(jo, null, "ignoreException", def.getIgnoreExceptions()); @@ -1645,8 +1645,8 @@ protected JsonObject doWriteRouteDefinition(RouteDefinition def) { doWriteAttribute(jo, "delayer", def.getDelayer(), null); doWriteAttribute(jo, "errorHandlerRef", def.getErrorHandlerRef(), null); doWriteAttribute(jo, "routePolicyRef", def.getRoutePolicyRef(), null); - doWriteAttribute(jo, "shutdownRoute", def.getShutdownRoute(), "Default"); - doWriteAttribute(jo, "shutdownRunningTask", def.getShutdownRunningTask(), "CompleteCurrentTaskOnly"); + doWriteAttribute(jo, "shutdownRoute", def.getShutdownRoute(), null); + doWriteAttribute(jo, "shutdownRunningTask", def.getShutdownRunningTask(), null); doWriteAttribute(jo, "precondition", def.getPrecondition(), null); doWriteChildList(jo, null, "routeProperty", def.getRouteProperties(), this::doWritePropertyDefinition); doWriteChildElement(jo, "errorHandler", def.getErrorHandler(), this::doWriteErrorHandlerDefinition); @@ -3358,14 +3358,14 @@ protected JsonObject doWriteRestBindingDefinition(RestBindingDefinition def) { doWriteOptionalIdentifiedDefinitionAttributes(jo, def); doWriteAttribute(jo, "consumes", def.getConsumes(), null); doWriteAttribute(jo, "produces", def.getProduces(), null); - doWriteAttribute(jo, "bindingMode", def.getBindingMode(), "off"); + doWriteAttribute(jo, "bindingMode", def.getBindingMode(), null); doWriteAttribute(jo, "type", def.getType(), null); doWriteAttribute(jo, "outType", def.getOutType(), null); - doWriteAttribute(jo, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute(jo, "clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute(jo, "clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute(jo, "enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute(jo, "enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute(jo, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute(jo, "clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute(jo, "clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute(jo, "enableCORS", def.getEnableCORS(), null); + doWriteAttribute(jo, "enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute(jo, "component", def.getComponent(), null); return jo; } @@ -3385,13 +3385,13 @@ protected JsonObject doWriteRestConfigurationDefinition(RestConfigurationDefinit doWriteAttribute(jo, "apiContextRouteId", def.getApiContextRouteId(), null); doWriteAttribute(jo, "apiVendorExtension", def.getApiVendorExtension(), "false"); doWriteAttribute(jo, "hostNameResolver", toString(def.getHostNameResolver()), "allLocalIp"); - doWriteAttribute(jo, "bindingMode", toString(def.getBindingMode()), "off"); + doWriteAttribute(jo, "bindingMode", toString(def.getBindingMode()), null); doWriteAttribute(jo, "bindingPackageScan", def.getBindingPackageScan(), null); - doWriteAttribute(jo, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute(jo, "clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute(jo, "clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute(jo, "enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute(jo, "enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute(jo, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute(jo, "clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute(jo, "clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute(jo, "enableCORS", def.getEnableCORS(), null); + doWriteAttribute(jo, "enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute(jo, "inlineRoutes", def.getInlineRoutes(), "true"); doWriteAttribute(jo, "jsonDataFormat", def.getJsonDataFormat(), "jackson"); doWriteAttribute(jo, "xmlDataFormat", def.getXmlDataFormat(), "jaxb"); @@ -3411,12 +3411,12 @@ protected JsonObject doWriteRestDefinition(RestDefinition def) { doWriteAttribute(jo, "path", def.getPath(), null); doWriteAttribute(jo, "consumes", def.getConsumes(), null); doWriteAttribute(jo, "produces", def.getProduces(), null); - doWriteAttribute(jo, "bindingMode", def.getBindingMode(), "off"); - doWriteAttribute(jo, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute(jo, "clientRequestValidation", def.getClientRequestValidation(), "false"); - doWriteAttribute(jo, "clientResponseValidation", def.getClientResponseValidation(), "false"); - doWriteAttribute(jo, "enableCORS", def.getEnableCORS(), "false"); - doWriteAttribute(jo, "enableNoContentResponse", def.getEnableNoContentResponse(), "false"); + doWriteAttribute(jo, "bindingMode", def.getBindingMode(), null); + doWriteAttribute(jo, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute(jo, "clientRequestValidation", def.getClientRequestValidation(), null); + doWriteAttribute(jo, "clientResponseValidation", def.getClientResponseValidation(), null); + doWriteAttribute(jo, "enableCORS", def.getEnableCORS(), null); + doWriteAttribute(jo, "enableNoContentResponse", def.getEnableNoContentResponse(), null); doWriteAttribute(jo, "apiDocs", def.getApiDocs(), "true"); doWriteAttribute(jo, "tag", def.getTag(), null); doWriteVerbs(jo, def.getVerbs(), this::doWriteVerbDefinition); @@ -3470,19 +3470,19 @@ protected JsonObject doWriteSecurityDefinition(SecurityDefinition def) { } protected void doWriteVerbDefinitionAttributes(JsonObject jo, VerbDefinition def) { doWriteOptionalIdentifiedDefinitionAttributes(jo, def); - doWriteAttribute(jo, "enableCORS", def.getEnableCORS(), "false"); + doWriteAttribute(jo, "enableCORS", def.getEnableCORS(), null); doWriteAttribute(jo, "deprecated", def.getDeprecated(), "false"); doWriteAttribute(jo, "streamCache", def.getStreamCache(), null); doWriteAttribute(jo, "type", def.getType(), null); doWriteAttribute(jo, "outType", def.getOutType(), null); - doWriteAttribute(jo, "clientResponseValidation", def.getClientResponseValidation(), "false"); + doWriteAttribute(jo, "clientResponseValidation", def.getClientResponseValidation(), null); doWriteAttribute(jo, "path", def.getPath(), null); doWriteAttribute(jo, "routeId", def.getRouteId(), null); - doWriteAttribute(jo, "bindingMode", def.getBindingMode(), "off"); + doWriteAttribute(jo, "bindingMode", def.getBindingMode(), null); doWriteAttribute(jo, "apiDocs", def.getApiDocs(), "true"); - doWriteAttribute(jo, "enableNoContentResponse", def.getEnableNoContentResponse(), "false"); - doWriteAttribute(jo, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), "false"); - doWriteAttribute(jo, "clientRequestValidation", def.getClientRequestValidation(), "false"); + doWriteAttribute(jo, "enableNoContentResponse", def.getEnableNoContentResponse(), null); + doWriteAttribute(jo, "skipBindingOnErrorCode", def.getSkipBindingOnErrorCode(), null); + doWriteAttribute(jo, "clientRequestValidation", def.getClientRequestValidation(), null); doWriteAttribute(jo, "produces", def.getProduces(), null); doWriteAttribute(jo, "disabled", def.getDisabled(), null); doWriteAttribute(jo, "consumes", def.getConsumes(), null); 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 0ecfc40763c77..1a7cd68bdff49 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 @@ -549,6 +549,16 @@ or follows, like Enter does. nothing), and a route that cannot be read, such as invalid YAML, exits with `1` and the error of the parser (it failed with an internal error, `70`, and a stack trace). +=== camel-xml-io, camel-yaml-io, camel-java-io - route dumps keep options set to their default value + +The XML, YAML and Java route dumps (`camel transform route`, `camel validate normalize`, `camel.main.dumpRoutes`, the +developer console) now write these options whenever they are set, also with their documented default value: the +binding options of the rest configuration, a rest and its verbs (such as `bindingMode="off"`), the options of a +redelivery policy, of a `resilience4jConfiguration` and of a `faultToleranceConfiguration`, and `shutdownRoute` / +`shutdownRunningTask` of a route. Left out, such an option took the value of the parent level when the dump was loaded +(the rest configuration, the error handler, the global circuit breaker configuration, the CamelContext), so the route +behaved differently. + === camel-jbang - camel get bean, get route-controller and top source * `camel get bean --dsl` shows the configuration of each property next to that property: it paired them by position, diff --git a/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlDumpExplicitDefaultValuesTest.java b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlDumpExplicitDefaultValuesTest.java new file mode 100644 index 0000000000000..7e051ac91d8f0 --- /dev/null +++ b/dsl/camel-xml-io-dsl/src/test/java/org/apache/camel/dsl/xml/io/XmlDumpExplicitDefaultValuesTest.java @@ -0,0 +1,181 @@ +/* + * 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.dsl.xml.io; + +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.component.seda.SedaEndpoint; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.model.RoutesDefinition; +import org.apache.camel.model.rest.RestsDefinition; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spi.RestConsumerFactory; +import org.apache.camel.support.PluginHelper; +import org.apache.camel.support.ResourceHelper; +import org.apache.camel.xml.LwModelToXMLDumper; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * A route that is dumped as XML and loaded again must behave as the route it was dumped from, also when an option is + * set to its documented default value, as an option that is not set takes the value of a parent level instead. + */ +class XmlDumpExplicitDefaultValuesTest { + + /** A rest consumer that receives from seda:verb-path, so the test can call a rest verb without an HTTP server. */ + public static class SedaRestConsumerFactory implements RestConsumerFactory { + @Override + public org.apache.camel.Consumer createConsumer( + CamelContext camelContext, Processor processor, String verb, String basePath, String uriTemplate, + String consumes, String produces, RestConfiguration configuration, Map parameters) + throws Exception { + String path = basePath + (uriTemplate != null ? uriTemplate : ""); + SedaEndpoint seda = camelContext.getEndpoint("seda:" + verb + path.replace('/', '-'), SedaEndpoint.class); + return seda.createConsumer(processor); + } + } + + @Test + void verbClientRequestValidationOffUnderRestConfiguration() throws Exception { + String xml = """ + + + + + + + + + + stored + + + + """; + Consumer setup = context -> { + context.getRegistry().bind("seda-rest", new SedaRestConsumerFactory()); + context.getRestConfiguration().setComponent("seda-rest"); + context.getRestConfiguration().setInlineRoutes(false); + // validation for all the rest services, the verb turns it off + context.getRestConfiguration().setClientRequestValidation(true); + }; + Function call = context -> { + Exchange reply = context.createProducerTemplate().request("seda:post-api-notes", e -> { + e.getMessage().setHeader(Exchange.CONTENT_TYPE, "text/plain"); + e.getMessage().setBody("a note"); + }); + return reply.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE, "200", String.class) + " " + + reply.getMessage().getBody(String.class); + }; + + assertEquals("200 stored", run(xml, setup, call)); + String dumped = dump(xml, setup); + assertEquals("200 stored", run(dumped, setup, call), dumped); + assertTrue(dumped.contains("clientRequestValidation=\"false\""), dumped); + } + + @Test + void onExceptionRedeliveryDelayUnderErrorHandler() throws Exception { + // the onException redelivers after 1000 ms (the documented default), the error handler after 30 s: an option + // of the onException that is not set takes the value of the error handler + String xml = """ + + + + + + + + + + java.lang.IllegalStateException + + + true + + + handled + + + + + + """; + Consumer setup = context -> context.getShutdownStrategy().setTimeout(1); + Function call = context -> { + try { + return context.createProducerTemplate().asyncRequestBody("direct:start", "x", String.class) + .get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + return "not redelivered within 10 seconds"; + } catch (Exception e) { + return e.toString(); + } + }; + + assertEquals("handled", run(xml, setup, call)); + String dumped = dump(xml, setup); + assertEquals("handled", run(dumped, setup, call), dumped); + } + + private static String run(String xml, Consumer setup, Function call) + throws Exception { + try (DefaultCamelContext context = new DefaultCamelContext()) { + setup.accept(context); + PluginHelper.getRoutesLoader(context).loadRoutes(ResourceHelper.fromString("routes.xml", xml)); + context.start(); + return call.apply(context); + } + } + + /** Loads the routes and rests, and dumps them back as one XML document. */ + private static String dump(String xml, Consumer setup) throws Exception { + try (DefaultCamelContext context = new DefaultCamelContext()) { + setup.accept(context); + PluginHelper.getRoutesLoader(context).loadRoutes(ResourceHelper.fromString("routes.xml", xml)); + ModelCamelContext model = (ModelCamelContext) context; + StringBuilder sb = new StringBuilder(""); + if (!model.getRestDefinitions().isEmpty()) { + RestsDefinition rests = new RestsDefinition(); + rests.getRests().addAll(model.getRestDefinitions()); + sb.append(body(new LwModelToXMLDumper().dumpModelAsXml(context, rests), "rests")); + } + RoutesDefinition routes = new RoutesDefinition(); + model.getRouteDefinitions().stream().filter(r -> !Boolean.TRUE.equals(r.isRest())) + .forEach(routes.getRoutes()::add); + sb.append(body(new LwModelToXMLDumper().dumpModelAsXml(context, routes), "routes")); + return sb.append("").toString(); + } + } + + /** The children of the root element of a dump. */ + private static String body(String dump, String root) { + int start = dump.indexOf('>', dump.indexOf("<" + root)) + 1; + int end = dump.lastIndexOf(""); + return dump.substring(start, end); + } +} diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/YamlDumpExplicitDefaultValuesTest.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/YamlDumpExplicitDefaultValuesTest.java new file mode 100644 index 0000000000000..54fb5f12244db --- /dev/null +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/java/org/apache/camel/dsl/yaml/YamlDumpExplicitDefaultValuesTest.java @@ -0,0 +1,209 @@ +/* + * 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.dsl.yaml; + +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.component.seda.SedaEndpoint; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.model.ModelCamelContext; +import org.apache.camel.model.RoutesDefinition; +import org.apache.camel.model.rest.RestsDefinition; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spi.RestConsumerFactory; +import org.apache.camel.support.PluginHelper; +import org.apache.camel.support.ResourceHelper; +import org.apache.camel.yaml.LwModelToYAMLDumper; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * A route that is dumped as YAML (camel validate normalize, camel transform route, the route dump) and loaded again + * must behave as the route it was dumped from, also when an option is set to its documented default value, as an option + * that is not set takes the value of a parent level instead. + */ +class YamlDumpExplicitDefaultValuesTest { + + /** A rest consumer that receives from seda:verb-path, so the test can call a rest verb without an HTTP server. */ + public static class SedaRestConsumerFactory implements RestConsumerFactory { + @Override + public org.apache.camel.Consumer createConsumer( + CamelContext camelContext, Processor processor, String verb, String basePath, String uriTemplate, + String consumes, String produces, RestConfiguration configuration, Map parameters) + throws Exception { + String path = basePath + (uriTemplate != null ? uriTemplate : ""); + SedaEndpoint seda = camelContext.getEndpoint("seda:" + verb + path.replace('/', '-'), SedaEndpoint.class); + return seda.createConsumer(processor); + } + } + + private static final Consumer JSON_BINDING = context -> { + context.getRegistry().bind("seda-rest", new SedaRestConsumerFactory()); + context.getRestConfiguration().setComponent("seda-rest"); + context.getRestConfiguration().setInlineRoutes(false); + context.getRestConfiguration().setBindingMode("json"); + }; + + @Test + void verbBindingModeOffUnderJsonRestConfiguration() throws Exception { + // the rest configuration binds json, this one verb turns binding off: its reply is not marshalled to json + String yaml = """ + - rest: + path: /api + get: + - path: /raw + bindingMode: "off" + to: direct:raw + - route: + from: + uri: direct:raw + steps: + - setBody: + expression: + simple: + expression: "${bean:type:java.util.Map.of('format', 'raw')}" + """; + Function call + = context -> context.createProducerTemplate().requestBody("seda:get-api-raw", "", String.class); + + assertThat(run(yaml, JSON_BINDING, call)).isEqualTo("{format=raw}"); + String dumped = dump(yaml, JSON_BINDING); + assertThat(run(dumped, JSON_BINDING, call)).as(dumped).isEqualTo("{format=raw}"); + assertThat(dumped).contains("bindingMode: \"off\""); + } + + @Test + void verbSkipBindingOnErrorCodeOff() throws Exception { + // skipBindingOnErrorCode is true when not set, though documented as false: the verb asks for its error + // replies to be bound to json as well + String yaml = """ + - rest: + path: /api + get: + - path: /err + skipBindingOnErrorCode: false + to: direct:err + - route: + from: + uri: direct:err + steps: + - setHeader: + name: CamelHttpResponseCode + expression: + constant: + expression: "400" + - setBody: + expression: + simple: + expression: "${bean:type:java.util.Map.of('error', 'bad request')}" + """; + Function call = context -> { + Exchange reply = context.createProducerTemplate().request("seda:get-api-err", e -> e.getMessage().setBody("")); + return reply.getMessage().getBody(String.class); + }; + + assertThat(run(yaml, JSON_BINDING, call)).isEqualTo("{\"error\":\"bad request\"}"); + String dumped = dump(yaml, JSON_BINDING); + assertThat(run(dumped, JSON_BINDING, call)).as(dumped).isEqualTo("{\"error\":\"bad request\"}"); + } + + @Test + void onExceptionRedeliveryDelayUnderErrorHandler() throws Exception { + // the onException redelivers after 1000 ms (the documented default), the error handler after 30 s: an option + // of the onException that is not set takes the value of the error handler + String yaml = """ + - onException: + exception: + - java.lang.IllegalStateException + redeliveryPolicy: + maximumRedeliveries: 1 + redeliveryDelay: 1000 + handled: + constant: + expression: "true" + steps: + - setBody: + expression: + constant: + expression: handled + - route: + errorHandler: + defaultErrorHandler: + redeliveryPolicy: + maximumRedeliveries: 3 + redeliveryDelay: 30000 + from: + uri: direct:start + steps: + - throwException: + exceptionType: java.lang.IllegalStateException + message: Forced + """; + Consumer setup = context -> context.getShutdownStrategy().setTimeout(1); + Function call = context -> { + try { + return context.createProducerTemplate().asyncRequestBody("direct:start", "x", String.class) + .get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + return "not redelivered within 10 seconds"; + } catch (Exception e) { + return e.toString(); + } + }; + + assertThat(run(yaml, setup, call)).isEqualTo("handled"); + String dumped = dump(yaml, setup); + assertThat(run(dumped, setup, call)).as(dumped).isEqualTo("handled"); + } + + private static String run(String yaml, Consumer setup, Function call) + throws Exception { + try (DefaultCamelContext context = new DefaultCamelContext()) { + setup.accept(context); + PluginHelper.getRoutesLoader(context).loadRoutes(ResourceHelper.fromString("routes.yaml", yaml)); + context.start(); + return call.apply(context); + } + } + + /** Loads the routes and rests, and dumps them back as YAML, as the route dump does. */ + private static String dump(String yaml, Consumer setup) throws Exception { + try (DefaultCamelContext context = new DefaultCamelContext()) { + setup.accept(context); + PluginHelper.getRoutesLoader(context).loadRoutes(ResourceHelper.fromString("routes.yaml", yaml)); + ModelCamelContext model = (ModelCamelContext) context; + StringBuilder sb = new StringBuilder(); + if (!model.getRestDefinitions().isEmpty()) { + RestsDefinition rests = new RestsDefinition(); + rests.getRests().addAll(model.getRestDefinitions()); + sb.append(new LwModelToYAMLDumper().dumpModelAsYaml(context, rests)).append('\n'); + } + RoutesDefinition routes = new RoutesDefinition(); + model.getRouteDefinitions().stream().filter(r -> !Boolean.TRUE.equals(r.isRest())) + .forEach(routes.getRoutes()::add); + return sb.append(new LwModelToYAMLDumper().dumpModelAsYaml(context, routes)).toString(); + } + } +} diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelWriterGeneratorMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelWriterGeneratorMojo.java index f375993b12de3..c772156f02899 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelWriterGeneratorMojo.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelWriterGeneratorMojo.java @@ -39,6 +39,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; @@ -493,6 +494,33 @@ private Stream> fieldReferences(Class clazz) { } public static class Property { + + /** + * The model classes of which every option is written whenever it is set, even to its documented default value: + * an onException copies the error handler's redelivery policy and overrides only the options that are set, and + * a circuit breaker configuration is layered over the global one, so "not set" means "the value of the parent + * level", not "the default value", and a dump that leaves such an option out runs differently once loaded. + */ + private static final Set INHERITED_OPTION_CLASSES = Set.of( + "org.apache.camel.model.RedeliveryPolicyDefinition", + "org.apache.camel.model.Resilience4jConfigurationCommon", + "org.apache.camel.model.FaultToleranceConfigurationCommon"); + + /** + * The options (declaring class and attribute name) that are written whenever they are set, for the same reason: + * the rest binding options of a verb take the value of its rest, then of the rest configuration, which in turn + * falls back to the RestConfiguration of the CamelContext; the shutdown options of a route take the value of + * the CamelContext. + */ + private static final Set INHERITED_OPTIONS = Stream.concat( + Stream.of("RestDefinition", "VerbDefinition", "RestBindingDefinition", "RestConfigurationDefinition") + .flatMap(c -> Stream.of("bindingMode", "skipBindingOnErrorCode", "clientRequestValidation", + "clientResponseValidation", "enableCORS", "enableNoContentResponse") + .map(o -> "org.apache.camel.model.rest." + c + "#" + o)), + Stream.of("org.apache.camel.model.RouteDefinition#shutdownRoute", + "org.apache.camel.model.RouteDefinition#shutdownRunningTask")) + .collect(Collectors.toUnmodifiableSet()); + private final Member field; private final Member getter; private final Member setter; @@ -618,7 +646,27 @@ public String getAttributeName() { return an; } + /** + * Whether "not set" means "the value of a parent level" for this option, see {@link #INHERITED_OPTIONS}. + */ + public boolean isInheritedOption() { + Member declaring = field != null ? field : members().findFirst().orElse(null); + if (declaring == null) { + return false; + } + String className = declaring.getDeclaringClass().getName(); + return INHERITED_OPTION_CLASSES.contains(className) || INHERITED_OPTIONS.contains(className + "#" + getName()); + } + + /** + * The default value as a Java literal, which the writers leave out, or the literal {@code null} when the option + * is always written when set (no default value, or an inherited option). + */ public String getDefaultValue() { + if (isInheritedOption()) { + // written whenever it is set, as "not set" means "the value of a parent level" + return "null"; + } String answer = null; Metadata m = getAnnotation(Metadata.class); if (m != null) {