This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 0e7071b98a6c4c0fb17dbeaa1a25952bf9078131 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu Oct 22 18:36:36 2020 +0200 CAMEL-15739: camel-core - Move AdviceWith from Reifier to Builder --- .../java/org/apache/camel/builder/AdviceWith.java | 174 +++++++++++++++++++++ .../apache/camel/builder/AdviceWithBuilder.java | 4 +- .../org/apache/camel/reifier/RouteReifier.java | 24 ++- 3 files changed, 187 insertions(+), 15 deletions(-) diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/builder/AdviceWith.java b/core/camel-core-engine/src/main/java/org/apache/camel/builder/AdviceWith.java new file mode 100644 index 0000000..a65ef80 --- /dev/null +++ b/core/camel-core-engine/src/main/java/org/apache/camel/builder/AdviceWith.java @@ -0,0 +1,174 @@ +/* + * 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.builder; + +import java.util.List; + +import org.apache.camel.CamelContext; +import org.apache.camel.ExtendedCamelContext; +import org.apache.camel.model.Model; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.model.RoutesDefinition; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Use this for using the advice with feature. + * + * Allows you to advice or enhance an existing route using a RouteBuilder style. For example you can add interceptors to + * intercept sending outgoing messages to assert those messages are as expected. + */ +public final class AdviceWith { + + private static final Logger LOG = LoggerFactory.getLogger(AdviceWith.class); + + private AdviceWith() { + } + + /** + * Advices this route with the route builder. + * <p/> + * <b>Important:</b> It is recommended to only advice a given route once (you can of course advice multiple routes). + * If you do it multiple times, then it may not work as expected, especially when any kind of error handling is + * involved. The Camel team plan for Camel 3.0 to support this as internal refactorings in the routing engine is + * needed to support this properly. + * <p/> + * You can use a regular {@link RouteBuilder} but the specialized {@link AdviceWithRouteBuilder} has additional + * features when using the <a href="http://camel.apache.org/advicewith.html">advice with</a> feature. We therefore + * suggest you to use the {@link AdviceWithRouteBuilder}. + * <p/> + * The advice process will add the interceptors, on exceptions, on completions etc. configured from the route + * builder to this route. + * <p/> + * This is mostly used for testing purpose to add interceptors and the likes to an existing route. + * <p/> + * Will stop and remove the old route from camel context and add and start this new advised route. + * + * @param definition the model definition + * @param camelContext the camel context + * @param builder the route builder + * @return a new route which is this route merged with the route builder + * @throws Exception can be thrown from the route builder + * @see AdviceWithRouteBuilder + */ + public static RouteDefinition adviceWith(RouteDefinition definition, CamelContext camelContext, RouteBuilder builder) + throws Exception { + ObjectHelper.notNull(definition, "RouteDefinition"); + ObjectHelper.notNull(camelContext, "CamelContext"); + ObjectHelper.notNull(builder, "RouteBuilder"); + + if (definition.getInput() == null) { + throw new IllegalArgumentException("RouteDefinition has no input"); + } + return doAdviceWith(definition, camelContext, builder); + } + + private static RouteDefinition doAdviceWith(RouteDefinition definition, CamelContext camelContext, RouteBuilder builder) + throws Exception { + ObjectHelper.notNull(builder, "RouteBuilder"); + + LOG.debug("AdviceWith route before: {}", definition); + ExtendedCamelContext ecc = camelContext.adapt(ExtendedCamelContext.class); + Model model = camelContext.getExtension(Model.class); + + // inject this route into the advice route builder so it can access this route + // and offer features to manipulate the route directly + if (builder instanceof AdviceWithRouteBuilder) { + AdviceWithRouteBuilder arb = (AdviceWithRouteBuilder) builder; + arb.setOriginalRoute(definition); + } + + // configure and prepare the routes from the builder + RoutesDefinition routes = builder.configureRoutes(camelContext); + + // was logging enabled or disabled + boolean logRoutesAsXml = true; + if (builder instanceof AdviceWithRouteBuilder) { + AdviceWithRouteBuilder arb = (AdviceWithRouteBuilder) builder; + logRoutesAsXml = arb.isLogRouteAsXml(); + } + + LOG.debug("AdviceWith routes: {}", routes); + + // we can only advice with a route builder without any routes + if (!builder.getRouteCollection().getRoutes().isEmpty()) { + throw new IllegalArgumentException( + "You can only advice from a RouteBuilder which has no existing routes. Remove all routes from the route builder."); + } + // we can not advice with error handlers (if you added a new error + // handler in the route builder) + // we must check the error handler on builder is not the same as on + // camel context, as that would be the default + // context scoped error handler, in case no error handlers was + // configured + if (builder.getRouteCollection().getErrorHandlerFactory() != null + && ecc.getErrorHandlerFactory() != builder.getRouteCollection().getErrorHandlerFactory()) { + throw new IllegalArgumentException( + "You can not advice with error handlers. Remove the error handlers from the route builder."); + } + + String beforeAsXml = null; + if (logRoutesAsXml && LOG.isInfoEnabled()) { + try { + beforeAsXml = ecc.getModelToXMLDumper().dumpModelAsXml(camelContext, definition); + } catch (Throwable e) { + // ignore, it may be due jaxb is not on classpath etc + } + } + + // stop and remove this existing route + model.removeRouteDefinition(definition); + + // any advice with tasks we should execute first? + if (builder instanceof AdviceWithRouteBuilder) { + List<AdviceWithTask> tasks = ((AdviceWithRouteBuilder) builder).getAdviceWithTasks(); + for (AdviceWithTask task : tasks) { + task.task(); + } + } + + // now merge which also ensures that interceptors and the likes get + // mixed in correctly as well + RouteDefinition merged = routes.route(definition); + + // add the new merged route + model.getRouteDefinitions().add(0, merged); + + // log the merged route at info level to make it easier to end users to + // spot any mistakes they may have made + if (LOG.isInfoEnabled()) { + LOG.info("AdviceWith route after: {}", merged); + } + + if (beforeAsXml != null && logRoutesAsXml && LOG.isInfoEnabled()) { + try { + String afterAsXml = ecc.getModelToXMLDumper().dumpModelAsXml(camelContext, merged); + LOG.info("Adviced route before/after as XML:\n{}\n{}", beforeAsXml, afterAsXml); + } catch (Throwable e) { + // ignore, it may be due jaxb is not on classpath etc + } + } + + // If the camel context is started then we start the route + if (camelContext.isStarted()) { + model.addRouteDefinition(merged); + } + return merged; + } + +} diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/builder/AdviceWithBuilder.java b/core/camel-core-engine/src/main/java/org/apache/camel/builder/AdviceWithBuilder.java index 4fc1a71..1756ecd 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/builder/AdviceWithBuilder.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/builder/AdviceWithBuilder.java @@ -21,7 +21,9 @@ import org.apache.camel.model.ProcessorDefinition; import org.apache.camel.model.RouteDefinition; /** - * A builder when using the <a href="http://camel.apache.org/advicewith.html">advice with</a> feature. + * A builder when using the advice with feature. + * + * @see AdviceWith */ public class AdviceWithBuilder<T extends ProcessorDefinition<?>> { diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/reifier/RouteReifier.java b/core/camel-core-engine/src/main/java/org/apache/camel/reifier/RouteReifier.java index 9cf9dd5..17fded9 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/reifier/RouteReifier.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/reifier/RouteReifier.java @@ -32,6 +32,7 @@ import org.apache.camel.Route; import org.apache.camel.RuntimeCamelException; import org.apache.camel.ShutdownRoute; import org.apache.camel.ShutdownRunningTask; +import org.apache.camel.builder.AdviceWith; import org.apache.camel.builder.AdviceWithRouteBuilder; import org.apache.camel.builder.AdviceWithTask; import org.apache.camel.builder.RouteBuilder; @@ -81,23 +82,18 @@ public class RouteReifier extends ProcessorReifier<RouteDefinition> { * <p/> * Will stop and remove the old route from camel context and add and start this new advised route. * - * @param definition the model definition - * @param camelContext the camel context - * @param builder the route builder - * @return a new route which is this route merged with the route builder - * @throws Exception can be thrown from the route builder - * @see AdviceWithRouteBuilder + * @param definition the model definition + * @param camelContext the camel context + * @param builder the route builder + * @return a new route which is this route merged with the route builder + * @throws Exception can be thrown from the route builder + * @see AdviceWithRouteBuilder + * @deprecated use {@link AdviceWith#adviceWith(RouteDefinition, CamelContext, RouteBuilder)} */ + @Deprecated public static RouteDefinition adviceWith(RouteDefinition definition, CamelContext camelContext, RouteBuilder builder) throws Exception { - ObjectHelper.notNull(definition, "RouteDefinition"); - ObjectHelper.notNull(camelContext, "CamelContext"); - ObjectHelper.notNull(builder, "RouteBuilder"); - - if (definition.getInput() == null) { - throw new IllegalArgumentException("RouteDefinition has no input"); - } - return new RouteReifier(camelContext, definition).adviceWith(builder); + return AdviceWith.adviceWith(definition, camelContext, builder); } @Override