From 36a514dc9e596dc7ca4e2f377251296acacc84e8 Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Thu, 25 Mar 2021 15:25:11 +0100 Subject: [PATCH 1/5] feat(core): global default error handler Adding a new configurer that will look for a camel.k.global-error-handler property that can be used to set a default global error handler. Any route builder will inherit this error handler unless it is explicitly specified. --- .../GlobalErrorHandlerConfigurer.java | 67 +++++++++++++++++++ .../org.apache.camel.k.Runtime$Listener | 1 + .../GlobalErrorHandlerConfigurerTest.java | 47 +++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 camel-k-core/support/src/main/java/org/apache/camel/k/listener/GlobalErrorHandlerConfigurer.java create mode 100644 camel-k-core/support/src/test/java/org/apache/camel/k/support/GlobalErrorHandlerConfigurerTest.java diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/GlobalErrorHandlerConfigurer.java b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/GlobalErrorHandlerConfigurer.java new file mode 100644 index 000000000..794f79491 --- /dev/null +++ b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/GlobalErrorHandlerConfigurer.java @@ -0,0 +1,67 @@ +/* + * 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.k.listener; + +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.builder.DeadLetterChannelBuilder; +import org.apache.camel.k.Runtime; +import org.apache.camel.k.support.PropertiesSupport; +import org.apache.camel.spi.Configurer; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Configurer +public class GlobalErrorHandlerConfigurer extends AbstractPhaseListener { + private static final Logger LOGGER = LoggerFactory.getLogger(GlobalErrorHandlerConfigurer.class); + + public static final String CAMEL_K_PREFIX = "camel.k."; + public static final String CAMEL_K_GLOBAL_ERROR_HANDLER_PREFIX = "camel.k.global-error-handler"; + + private String globalErrorHandler; + + public GlobalErrorHandlerConfigurer() { + super(Runtime.Phase.ConfigureRoutes); + } + + public String getGlobalErrorHandler(){ + return this.globalErrorHandler; + } + + public void setGlobalErrorHandler(String globalErrorHandler){ + this.globalErrorHandler = globalErrorHandler; + } + + @Override + protected void accept(Runtime runtime) { + PropertiesSupport.bindProperties( + runtime.getCamelContext(), + this, + k -> k.startsWith(CAMEL_K_GLOBAL_ERROR_HANDLER_PREFIX), + CAMEL_K_PREFIX); + if (ObjectHelper.isNotEmpty(this.globalErrorHandler)) { + loadGlobalErrorHandler(runtime, this.getGlobalErrorHandler()); + } + } + + public static void loadGlobalErrorHandler(Runtime runtime, String uri) { + LOGGER.info("Setting a default global error handler factory to deadletter channel {}", uri); + runtime.getCamelContext().adapt(ExtendedCamelContext.class) + .setErrorHandlerFactory(new DeadLetterChannelBuilder(uri)); + } + +} diff --git a/camel-k-core/support/src/main/resources/META-INF/services/org.apache.camel.k.Runtime$Listener b/camel-k-core/support/src/main/resources/META-INF/services/org.apache.camel.k.Runtime$Listener index f0c50b74f..9fc5078f2 100644 --- a/camel-k-core/support/src/main/resources/META-INF/services/org.apache.camel.k.Runtime$Listener +++ b/camel-k-core/support/src/main/resources/META-INF/services/org.apache.camel.k.Runtime$Listener @@ -16,5 +16,6 @@ # org.apache.camel.k.listener.ContextConfigurer +org.apache.camel.k.listener.GlobalErrorHandlerConfigurer org.apache.camel.k.listener.SourcesConfigurer org.apache.camel.k.listener.PropertiesConfigurer diff --git a/camel-k-core/support/src/test/java/org/apache/camel/k/support/GlobalErrorHandlerConfigurerTest.java b/camel-k-core/support/src/test/java/org/apache/camel/k/support/GlobalErrorHandlerConfigurerTest.java new file mode 100644 index 000000000..fdb7446f7 --- /dev/null +++ b/camel-k-core/support/src/test/java/org/apache/camel/k/support/GlobalErrorHandlerConfigurerTest.java @@ -0,0 +1,47 @@ +/* + * 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.k.support; + +import org.apache.camel.CamelContext; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.k.listener.GlobalErrorHandlerConfigurer; +import org.apache.camel.k.listener.SourcesConfigurer; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.k.test.CamelKTestSupport.asProperties; +import static org.assertj.core.api.Assertions.assertThat; + +public class GlobalErrorHandlerConfigurerTest { + + @Test + public void globalErrorHandlerIsBoundToSourcesConfigurer() { + CamelContext context = new DefaultCamelContext(); + context.getPropertiesComponent().setInitialProperties(asProperties( + "camel.k.global-error-handler", "someUriError" + )); + + GlobalErrorHandlerConfigurer configuration = new GlobalErrorHandlerConfigurer(); + + PropertiesSupport.bindProperties( + context, + configuration, + k -> k.startsWith(GlobalErrorHandlerConfigurer.CAMEL_K_GLOBAL_ERROR_HANDLER_PREFIX), + SourcesConfigurer.CAMEL_K_PREFIX); + + assertThat(configuration.getGlobalErrorHandler()).isEqualTo("someUriError"); + } +} From 00121ebe966b0c02c812aa29a788d1d63c449b6e Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Tue, 13 Apr 2021 12:45:48 +0200 Subject: [PATCH 2/5] feat(core): default error handler * Introduced a new SourceType, errorHandler, that can be used as a source for spotting a default error handler that will be used in those routes that don't specify any * Forced the sources sorting in order to load errorHandler first, sources and templates * Added a check to make sure only one error handler is provided --- .../java/org/apache/camel/k/SourceType.java | 2 + .../GlobalErrorHandlerConfigurer.java | 67 ---------- .../camel/k/listener/SourcesConfigurer.java | 42 ++++++- .../camel/k/support/SourcesSupport.java | 59 +++++++-- .../org.apache.camel.k.Runtime$Listener | 1 - .../k/listener/SourceConfigurerTest.java | 114 ++++++++++++++++++ .../GlobalErrorHandlerConfigurerTest.java | 47 -------- 7 files changed, 206 insertions(+), 126 deletions(-) delete mode 100644 camel-k-core/support/src/main/java/org/apache/camel/k/listener/GlobalErrorHandlerConfigurer.java create mode 100644 camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java delete mode 100644 camel-k-core/support/src/test/java/org/apache/camel/k/support/GlobalErrorHandlerConfigurerTest.java diff --git a/camel-k-core/api/src/main/java/org/apache/camel/k/SourceType.java b/camel-k-core/api/src/main/java/org/apache/camel/k/SourceType.java index ed9717a28..243a7b877 100644 --- a/camel-k-core/api/src/main/java/org/apache/camel/k/SourceType.java +++ b/camel-k-core/api/src/main/java/org/apache/camel/k/SourceType.java @@ -17,6 +17,8 @@ package org.apache.camel.k; public enum SourceType { + // Order matters. We want the sources to be loaded following this enum order. + errorHandler, source, template } diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/GlobalErrorHandlerConfigurer.java b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/GlobalErrorHandlerConfigurer.java deleted file mode 100644 index 794f79491..000000000 --- a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/GlobalErrorHandlerConfigurer.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.k.listener; - -import org.apache.camel.ExtendedCamelContext; -import org.apache.camel.builder.DeadLetterChannelBuilder; -import org.apache.camel.k.Runtime; -import org.apache.camel.k.support.PropertiesSupport; -import org.apache.camel.spi.Configurer; -import org.apache.camel.util.ObjectHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Configurer -public class GlobalErrorHandlerConfigurer extends AbstractPhaseListener { - private static final Logger LOGGER = LoggerFactory.getLogger(GlobalErrorHandlerConfigurer.class); - - public static final String CAMEL_K_PREFIX = "camel.k."; - public static final String CAMEL_K_GLOBAL_ERROR_HANDLER_PREFIX = "camel.k.global-error-handler"; - - private String globalErrorHandler; - - public GlobalErrorHandlerConfigurer() { - super(Runtime.Phase.ConfigureRoutes); - } - - public String getGlobalErrorHandler(){ - return this.globalErrorHandler; - } - - public void setGlobalErrorHandler(String globalErrorHandler){ - this.globalErrorHandler = globalErrorHandler; - } - - @Override - protected void accept(Runtime runtime) { - PropertiesSupport.bindProperties( - runtime.getCamelContext(), - this, - k -> k.startsWith(CAMEL_K_GLOBAL_ERROR_HANDLER_PREFIX), - CAMEL_K_PREFIX); - if (ObjectHelper.isNotEmpty(this.globalErrorHandler)) { - loadGlobalErrorHandler(runtime, this.getGlobalErrorHandler()); - } - } - - public static void loadGlobalErrorHandler(Runtime runtime, String uri) { - LOGGER.info("Setting a default global error handler factory to deadletter channel {}", uri); - runtime.getCamelContext().adapt(ExtendedCamelContext.class) - .setErrorHandlerFactory(new DeadLetterChannelBuilder(uri)); - } - -} diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java index 30c2efe73..95ddd929d 100644 --- a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java +++ b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java @@ -18,12 +18,16 @@ import org.apache.camel.k.Runtime; import org.apache.camel.k.SourceDefinition; +import org.apache.camel.k.SourceType; import org.apache.camel.k.support.Constants; import org.apache.camel.k.support.PropertiesSupport; import org.apache.camel.k.support.SourcesSupport; import org.apache.camel.spi.Configurer; import org.apache.camel.util.ObjectHelper; +import java.util.Arrays; +import java.util.Collections; + @Configurer public class SourcesConfigurer extends AbstractPhaseListener { public static final String CAMEL_K_PREFIX = "camel.k."; @@ -64,14 +68,44 @@ protected void accept(Runtime runtime) { // property that can't be bound to this configurer. // PropertiesSupport.bindProperties( - runtime.getCamelContext(), - this, - k -> k.startsWith(CAMEL_K_SOURCES_PREFIX), - CAMEL_K_PREFIX); + runtime.getCamelContext(), + this, + k -> k.startsWith(CAMEL_K_SOURCES_PREFIX), + CAMEL_K_PREFIX); + + checkUniqueErrorHandler(); + sortSources(); if (ObjectHelper.isNotEmpty(this.getSources())) { SourcesSupport.loadSources(runtime, this.getSources()); } } + private void checkUniqueErrorHandler() { + checkUniqueErrorHandler(this.sources); + } + + static void checkUniqueErrorHandler(SourceDefinition[] sources) { + long errorHandlers = Arrays.stream(sources).filter(s -> s.getType() == SourceType.errorHandler).count(); + if ( errorHandlers > 1) { + throw new IllegalArgumentException("Expected only one error handler source type, got " + errorHandlers); + } + } + + private void sortSources() { + sortSources(this.getSources()); + } + + static void sortSources(SourceDefinition[] sources) { + // We must ensure the following source type order: errorHandler, source, template + Arrays.sort(sources, + (a, b) -> { + if (a.getType() == null) { + return SourceType.source.compareTo(b.getType()); + } else if (b.getType() == null) { + return a.getType().compareTo(SourceType.source); + } else return a.getType().compareTo(b.getType()); + }); + } + } diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java b/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java index e3935212f..029b4d3bb 100644 --- a/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java +++ b/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java @@ -16,12 +16,10 @@ */ package org.apache.camel.k.support; -import java.util.Collection; -import java.util.List; - import org.apache.camel.ExtendedCamelContext; import org.apache.camel.RoutesBuilder; import org.apache.camel.RuntimeCamelException; +import org.apache.camel.builder.ErrorHandlerBuilder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.builder.RouteBuilderLifecycleStrategy; import org.apache.camel.k.Runtime; @@ -37,6 +35,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.List; + public final class SourcesSupport { private static final Logger LOGGER = LoggerFactory.getLogger(SourcesConfigurer.class); @@ -128,21 +130,64 @@ public void afterConfigure(RouteBuilder builder) { } }); break; + case errorHandler: + if (!source.getInterceptors().isEmpty()) { + LOGGER.warn("Interceptors associated to the route template {} will be ignored", source.getName()); + } + + interceptors = List.of(new RouteBuilderLifecycleStrategy() { + @Override + public void afterConfigure(RouteBuilder builder) { + List routes = builder.getRouteCollection().getRoutes(); + List templates = builder.getRouteTemplateCollection().getRouteTemplates(); + + if (routes.size() > 0) { + throw new IllegalArgumentException("There should be no route definition, got " + routes.size()); + } + if (!templates.isEmpty()) { + throw new IllegalArgumentException("There should not be any template, got " + templates.size()); + } + + if (existErrorHandler(builder)) { + LOGGER.debug("Setting default error handler builder factory as {}", builder.getErrorHandlerBuilder()); + runtime.getCamelContext().adapt(ExtendedCamelContext.class).setErrorHandlerFactory(builder.getErrorHandlerBuilder()); + } + } + }); + break; default: throw new IllegalArgumentException("Unknown source type: " + source.getType()); } try { final Resource resource = Sources.asResource(runtime.getCamelContext(), source); - final ExtendedCamelContext ecc = runtime.getCamelContext(ExtendedCamelContext.class); + final ExtendedCamelContext ecc = runtime.getCamelContext(ExtendedCamelContext.class); final Collection builders = ecc.getRoutesLoader().findRoutesBuilders(resource); builders.stream() - .map(RouteBuilder.class::cast) - .peek(b -> interceptors.forEach(b::addLifecycleInterceptor)) - .forEach(runtime::addRoutes); + .map(RouteBuilder.class::cast) + .peek(b -> interceptors.forEach(b::addLifecycleInterceptor)) + .forEach(runtime::addRoutes); } catch (Exception e) { throw RuntimeCamelException.wrapRuntimeCamelException(e); } } + + static boolean existErrorHandler(RouteBuilder builder) { + //return builder.hasErrorHandlerBuilder(); + // TODO We need to replace the following workaround with the statement above once we switch to camel-3.10.0 or above + try { + Field f = RouteBuilder.class.getSuperclass().getDeclaredField("errorHandlerBuilder"); + f.setAccessible(true); + ErrorHandlerBuilder privateErrorHandlerBuilder = (ErrorHandlerBuilder) f.get(builder); + return privateErrorHandlerBuilder != null; + } catch (Exception e){ + throw new IllegalArgumentException("Something went wrong while checking the error handler builder", e); + } + } + + public static void loadErrorHandlerSource(Runtime runtime, SourceDefinition errorHandlerSourceDefinition) { + LOGGER.info("Loading error handler from: {}", errorHandlerSourceDefinition); + load(runtime, Sources.fromDefinition(errorHandlerSourceDefinition)); + } } diff --git a/camel-k-core/support/src/main/resources/META-INF/services/org.apache.camel.k.Runtime$Listener b/camel-k-core/support/src/main/resources/META-INF/services/org.apache.camel.k.Runtime$Listener index 9fc5078f2..f0c50b74f 100644 --- a/camel-k-core/support/src/main/resources/META-INF/services/org.apache.camel.k.Runtime$Listener +++ b/camel-k-core/support/src/main/resources/META-INF/services/org.apache.camel.k.Runtime$Listener @@ -16,6 +16,5 @@ # org.apache.camel.k.listener.ContextConfigurer -org.apache.camel.k.listener.GlobalErrorHandlerConfigurer org.apache.camel.k.listener.SourcesConfigurer org.apache.camel.k.listener.PropertiesConfigurer diff --git a/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java b/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java new file mode 100644 index 000000000..ebdd22c5e --- /dev/null +++ b/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java @@ -0,0 +1,114 @@ +/* + * 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.k.listener; + +import org.apache.camel.CamelContext; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.k.support.PropertiesSupport; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.k.test.CamelKTestSupport.asProperties; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class SourceConfigurerTest { + @Test + public void shouldLoadMultipleSources() { + CamelContext context = new DefaultCamelContext(); + context.getPropertiesComponent().setInitialProperties(asProperties( + "camel.k.sources[0].name", "sourceName0", + "camel.k.sources[0].location", "classpath:MyTemplate1.java", + "camel.k.sources[0].type", "template", + "camel.k.sources[1].name", "err1", + "camel.k.sources[1.location", "classpath:MyTemplate2.java", + "camel.k.sources[2].name", "err2", + "camel.k.sources[2].location", "classpath:Err2.java", + "camel.k.sources[2].type", "errorHandler" + )); + + SourcesConfigurer configuration = new SourcesConfigurer(); + + PropertiesSupport.bindProperties( + context, + configuration, + k -> k.startsWith(SourcesConfigurer.CAMEL_K_SOURCES_PREFIX), + SourcesConfigurer.CAMEL_K_PREFIX); + + assertThat(configuration.getSources().length).isEqualTo(3); + } + + @Test + public void shouldFailOnMultipleErrorHandlers() { + CamelContext context = new DefaultCamelContext(); + context.getPropertiesComponent().setInitialProperties(asProperties( + "camel.k.sources[0].name", "sourceName0", + "camel.k.sources[0].location", "classpath:MyTemplate1.java", + "camel.k.sources[0].type", "template", + "camel.k.sources[1].name", "err1", + "camel.k.sources[1.location", "classpath:Err1.java", + "camel.k.sources[1].type", "errorHandler", + "camel.k.sources[2].name", "err2", + "camel.k.sources[2].location", "classpath:Err2.java", + "camel.k.sources[2].type", "errorHandler" + )); + + SourcesConfigurer configuration = new SourcesConfigurer(); + + PropertiesSupport.bindProperties( + context, + configuration, + k -> k.startsWith(SourcesConfigurer.CAMEL_K_SOURCES_PREFIX), + SourcesConfigurer.CAMEL_K_PREFIX); + + assertThat(configuration.getSources().length).isEqualTo(3); + Assertions.assertThrows(IllegalArgumentException.class, () -> { + SourcesConfigurer.checkUniqueErrorHandler(configuration.getSources()); + }, "java.lang.IllegalArgumentException: Expected only one error handler source type, got 2"); + } + + @Test + public void shouldOrderSourcesByType() { + CamelContext context = new DefaultCamelContext(); + context.getPropertiesComponent().setInitialProperties(asProperties( + "camel.k.sources[0].name", "template1", + "camel.k.sources[0].type", "template", + "camel.k.sources[1].name", "source1", + "camel.k.sources[2].name", "source2", + "camel.k.sources[2].type", "source", + "camel.k.sources[3].name", "errorHandler1", + "camel.k.sources[3].type", "errorHandler" + )); + + SourcesConfigurer configuration = new SourcesConfigurer(); + + PropertiesSupport.bindProperties( + context, + configuration, + k -> k.startsWith(SourcesConfigurer.CAMEL_K_SOURCES_PREFIX), + SourcesConfigurer.CAMEL_K_PREFIX); + SourcesConfigurer.sortSources(configuration.getSources()); + + assertThat(configuration.getSources().length).isEqualTo(4); + + assertThat(configuration.getSources()[0].getName()).isEqualTo("errorHandler1"); + // Order for the same type does not matter + assertThat(configuration.getSources()[1].getName()).contains("source"); + assertThat(configuration.getSources()[2].getName()).contains("source"); + assertThat(configuration.getSources()[3].getName()).isEqualTo("template1"); + } +} diff --git a/camel-k-core/support/src/test/java/org/apache/camel/k/support/GlobalErrorHandlerConfigurerTest.java b/camel-k-core/support/src/test/java/org/apache/camel/k/support/GlobalErrorHandlerConfigurerTest.java deleted file mode 100644 index fdb7446f7..000000000 --- a/camel-k-core/support/src/test/java/org/apache/camel/k/support/GlobalErrorHandlerConfigurerTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.k.support; - -import org.apache.camel.CamelContext; -import org.apache.camel.impl.DefaultCamelContext; -import org.apache.camel.k.listener.GlobalErrorHandlerConfigurer; -import org.apache.camel.k.listener.SourcesConfigurer; -import org.junit.jupiter.api.Test; - -import static org.apache.camel.k.test.CamelKTestSupport.asProperties; -import static org.assertj.core.api.Assertions.assertThat; - -public class GlobalErrorHandlerConfigurerTest { - - @Test - public void globalErrorHandlerIsBoundToSourcesConfigurer() { - CamelContext context = new DefaultCamelContext(); - context.getPropertiesComponent().setInitialProperties(asProperties( - "camel.k.global-error-handler", "someUriError" - )); - - GlobalErrorHandlerConfigurer configuration = new GlobalErrorHandlerConfigurer(); - - PropertiesSupport.bindProperties( - context, - configuration, - k -> k.startsWith(GlobalErrorHandlerConfigurer.CAMEL_K_GLOBAL_ERROR_HANDLER_PREFIX), - SourcesConfigurer.CAMEL_K_PREFIX); - - assertThat(configuration.getGlobalErrorHandler()).isEqualTo("someUriError"); - } -} From 7cb17fa90d3a71d3a48ef0a1bbb12212f3bd5eb8 Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Tue, 13 Apr 2021 14:27:03 +0200 Subject: [PATCH 3/5] fix(core): NPE on error handler source sorting --- .../org/apache/camel/k/listener/SourcesConfigurer.java | 7 +++++-- .../java/org/apache/camel/k/support/SourcesSupport.java | 6 +++--- .../org/apache/camel/k/listener/SourceConfigurerTest.java | 6 ++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java index 95ddd929d..4360ed2b5 100644 --- a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java +++ b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java @@ -86,8 +86,8 @@ private void checkUniqueErrorHandler() { } static void checkUniqueErrorHandler(SourceDefinition[] sources) { - long errorHandlers = Arrays.stream(sources).filter(s -> s.getType() == SourceType.errorHandler).count(); - if ( errorHandlers > 1) { + long errorHandlers = sources == null ? 0 : Arrays.stream(sources).filter(s -> s.getType() == SourceType.errorHandler).count(); + if (errorHandlers > 1) { throw new IllegalArgumentException("Expected only one error handler source type, got " + errorHandlers); } } @@ -97,6 +97,9 @@ private void sortSources() { } static void sortSources(SourceDefinition[] sources) { + if (sources == null) { + return; + } // We must ensure the following source type order: errorHandler, source, template Arrays.sort(sources, (a, b) -> { diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java b/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java index 029b4d3bb..c98744d7f 100644 --- a/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java +++ b/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java @@ -64,7 +64,7 @@ protected void accept(Runtime runtime) { } public static void loadSources(Runtime runtime, String... routes) { - for (String route: routes) { + for (String route : routes) { if (ObjectHelper.isEmpty(route)) { continue; } @@ -80,7 +80,7 @@ public static void loadSources(Runtime runtime, String... routes) { } public static void loadSources(Runtime runtime, SourceDefinition... definitions) { - for (SourceDefinition definition: definitions) { + for (SourceDefinition definition : definitions) { LOGGER.info("Loading routes from: {}", definition); load(runtime, Sources.fromDefinition(definition)); @@ -181,7 +181,7 @@ static boolean existErrorHandler(RouteBuilder builder) { f.setAccessible(true); ErrorHandlerBuilder privateErrorHandlerBuilder = (ErrorHandlerBuilder) f.get(builder); return privateErrorHandlerBuilder != null; - } catch (Exception e){ + } catch (Exception e) { throw new IllegalArgumentException("Something went wrong while checking the error handler builder", e); } } diff --git a/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java b/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java index ebdd22c5e..44f9f7cf3 100644 --- a/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java +++ b/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java @@ -111,4 +111,10 @@ public void shouldOrderSourcesByType() { assertThat(configuration.getSources()[2].getName()).contains("source"); assertThat(configuration.getSources()[3].getName()).isEqualTo("template1"); } + + @Test + public void shouldNotFailOnEmptySources() { + SourcesConfigurer.sortSources(null); + SourcesConfigurer.checkUniqueErrorHandler(null); + } } From af4927a364460d0ce8eed628fb9d5d2e62f5912d Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Tue, 13 Apr 2021 14:47:49 +0200 Subject: [PATCH 4/5] chore(core): checkstyle fixes --- .../java/org/apache/camel/k/listener/SourcesConfigurer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java index 4360ed2b5..db0fb2448 100644 --- a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java +++ b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java @@ -26,7 +26,6 @@ import org.apache.camel.util.ObjectHelper; import java.util.Arrays; -import java.util.Collections; @Configurer public class SourcesConfigurer extends AbstractPhaseListener { @@ -107,7 +106,9 @@ static void sortSources(SourceDefinition[] sources) { return SourceType.source.compareTo(b.getType()); } else if (b.getType() == null) { return a.getType().compareTo(SourceType.source); - } else return a.getType().compareTo(b.getType()); + } else { + return a.getType().compareTo(b.getType()); + } }); } From 088c3cd52e811077e01328a0acafa30b0ddc3684 Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Tue, 13 Apr 2021 14:56:16 +0200 Subject: [PATCH 5/5] fix(core): SourceType enum order --- .../src/main/java/org/apache/camel/k/SourceType.java | 4 ++-- .../apache/camel/k/listener/SourcesConfigurer.java | 6 +++--- .../org/apache/camel/k/support/SourcesSupport.java | 12 ++++++------ .../camel/k/listener/SourceConfigurerTest.java | 9 ++++----- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/camel-k-core/api/src/main/java/org/apache/camel/k/SourceType.java b/camel-k-core/api/src/main/java/org/apache/camel/k/SourceType.java index 243a7b877..c06250ae5 100644 --- a/camel-k-core/api/src/main/java/org/apache/camel/k/SourceType.java +++ b/camel-k-core/api/src/main/java/org/apache/camel/k/SourceType.java @@ -19,6 +19,6 @@ public enum SourceType { // Order matters. We want the sources to be loaded following this enum order. errorHandler, - source, - template + template, + source } diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java index db0fb2448..cbaae0508 100644 --- a/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java +++ b/camel-k-core/support/src/main/java/org/apache/camel/k/listener/SourcesConfigurer.java @@ -16,6 +16,8 @@ */ package org.apache.camel.k.listener; +import java.util.Arrays; + import org.apache.camel.k.Runtime; import org.apache.camel.k.SourceDefinition; import org.apache.camel.k.SourceType; @@ -25,8 +27,6 @@ import org.apache.camel.spi.Configurer; import org.apache.camel.util.ObjectHelper; -import java.util.Arrays; - @Configurer public class SourcesConfigurer extends AbstractPhaseListener { public static final String CAMEL_K_PREFIX = "camel.k."; @@ -99,7 +99,7 @@ static void sortSources(SourceDefinition[] sources) { if (sources == null) { return; } - // We must ensure the following source type order: errorHandler, source, template + // We must ensure the source order as defined in SourceType enum Arrays.sort(sources, (a, b) -> { if (a.getType() == null) { diff --git a/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java b/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java index c98744d7f..397dcb8cb 100644 --- a/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java +++ b/camel-k-core/support/src/main/java/org/apache/camel/k/support/SourcesSupport.java @@ -16,6 +16,10 @@ */ package org.apache.camel.k.support; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.List; + import org.apache.camel.ExtendedCamelContext; import org.apache.camel.RoutesBuilder; import org.apache.camel.RuntimeCamelException; @@ -35,10 +39,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.Field; -import java.util.Collection; -import java.util.List; - public final class SourcesSupport { private static final Logger LOGGER = LoggerFactory.getLogger(SourcesConfigurer.class); @@ -148,7 +148,7 @@ public void afterConfigure(RouteBuilder builder) { throw new IllegalArgumentException("There should not be any template, got " + templates.size()); } - if (existErrorHandler(builder)) { + if (hasErrorHandlerBuilder(builder)) { LOGGER.debug("Setting default error handler builder factory as {}", builder.getErrorHandlerBuilder()); runtime.getCamelContext().adapt(ExtendedCamelContext.class).setErrorHandlerFactory(builder.getErrorHandlerBuilder()); } @@ -173,7 +173,7 @@ public void afterConfigure(RouteBuilder builder) { } } - static boolean existErrorHandler(RouteBuilder builder) { + static boolean hasErrorHandlerBuilder(RouteBuilder builder) { //return builder.hasErrorHandlerBuilder(); // TODO We need to replace the following workaround with the statement above once we switch to camel-3.10.0 or above try { diff --git a/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java b/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java index 44f9f7cf3..2aae80e8d 100644 --- a/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java +++ b/camel-k-core/support/src/test/java/org/apache/camel/k/listener/SourceConfigurerTest.java @@ -35,7 +35,7 @@ public void shouldLoadMultipleSources() { "camel.k.sources[0].location", "classpath:MyTemplate1.java", "camel.k.sources[0].type", "template", "camel.k.sources[1].name", "err1", - "camel.k.sources[1.location", "classpath:MyTemplate2.java", + "camel.k.sources[1].location", "classpath:MyTemplate2.java", "camel.k.sources[2].name", "err2", "camel.k.sources[2].location", "classpath:Err2.java", "camel.k.sources[2].type", "errorHandler" @@ -60,7 +60,7 @@ public void shouldFailOnMultipleErrorHandlers() { "camel.k.sources[0].location", "classpath:MyTemplate1.java", "camel.k.sources[0].type", "template", "camel.k.sources[1].name", "err1", - "camel.k.sources[1.location", "classpath:Err1.java", + "camel.k.sources[1].location", "classpath:Err1.java", "camel.k.sources[1].type", "errorHandler", "camel.k.sources[2].name", "err2", "camel.k.sources[2].location", "classpath:Err2.java", @@ -104,12 +104,11 @@ public void shouldOrderSourcesByType() { SourcesConfigurer.sortSources(configuration.getSources()); assertThat(configuration.getSources().length).isEqualTo(4); - assertThat(configuration.getSources()[0].getName()).isEqualTo("errorHandler1"); + assertThat(configuration.getSources()[1].getName()).isEqualTo("template1"); // Order for the same type does not matter - assertThat(configuration.getSources()[1].getName()).contains("source"); assertThat(configuration.getSources()[2].getName()).contains("source"); - assertThat(configuration.getSources()[3].getName()).isEqualTo("template1"); + assertThat(configuration.getSources()[3].getName()).contains("source"); } @Test