This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 0b0663e95d6419ffce34aeebb005c174bc0c1466 Author: Guillaume Nodet <[email protected]> AuthorDate: Fri May 24 18:05:43 2019 +0200 [CAMEL-13564] Move error handler processors to camel-base --- .../transaction/JtaTransactionErrorHandler.java | 2 +- .../cdi/transaction/TransactionErrorHandler.java | 2 +- .../camel/spring/spi/TransactionErrorHandler.java | 2 +- .../processor/errorhandler/DeadLetterChannel.java | 1 - .../errorhandler/DefaultErrorHandler.java | 1 - .../DefaultExceptionPolicyStrategy.java | 80 +++---- .../errorhandler/ErrorHandlerSupport.java | 9 +- .../processor/errorhandler/ExceptionPolicy.java | 261 +++++++++++++++++++++ .../errorhandler}/ExceptionPolicyKey.java | 4 +- .../errorhandler}/ExceptionPolicyStrategy.java | 13 +- .../errorhandler/RedeliveryErrorHandler.java | 1 - .../processor/errorhandler/RedeliveryPolicy.java | 0 .../camel/processor/errorhandler}/package.html | 0 .../apache/camel/builder/ErrorHandlerBuilder.java | 2 +- .../camel/builder/ErrorHandlerBuilderSupport.java | 15 +- .../processor/exceptionpolicy/ExceptionPolicy.java | 85 ------- .../apache/camel/reifier/DynamicRouterReifier.java | 2 +- .../apache/camel/reifier/OnExceptionReifier.java | 1 - .../errorhandler/DefaultErrorHandlerReifier.java | 6 - .../reifier/errorhandler/ErrorHandlerReifier.java | 109 +++++---- .../CustomExceptionPolicyStrategyTest.java | 12 +- .../DefaultExceptionPolicyStrategyTest.java | 63 +++-- 22 files changed, 427 insertions(+), 244 deletions(-) diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/JtaTransactionErrorHandler.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/JtaTransactionErrorHandler.java index 915b7b0..19e9f9a 100644 --- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/JtaTransactionErrorHandler.java +++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/JtaTransactionErrorHandler.java @@ -24,7 +24,7 @@ import org.apache.camel.Predicate; import org.apache.camel.Processor; import org.apache.camel.processor.errorhandler.RedeliveryErrorHandler; import org.apache.camel.processor.errorhandler.RedeliveryPolicy; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; +import org.apache.camel.processor.errorhandler.ExceptionPolicyStrategy; import org.apache.camel.spi.CamelLogger; /** diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/TransactionErrorHandler.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/TransactionErrorHandler.java index c8f43ae..deb42af 100644 --- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/TransactionErrorHandler.java +++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/TransactionErrorHandler.java @@ -32,7 +32,7 @@ import org.apache.camel.Navigate; import org.apache.camel.Processor; import org.apache.camel.RuntimeCamelException; import org.apache.camel.processor.errorhandler.ErrorHandlerSupport; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; +import org.apache.camel.processor.errorhandler.ExceptionPolicyStrategy; import org.apache.camel.spi.ShutdownPrepared; import org.apache.camel.support.AsyncCallbackToCompletableFutureAdapter; import org.apache.camel.support.ExchangeHelper; diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/spi/TransactionErrorHandler.java b/components/camel-spring/src/main/java/org/apache/camel/spring/spi/TransactionErrorHandler.java index c6be3d7..7a06af2 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/spring/spi/TransactionErrorHandler.java +++ b/components/camel-spring/src/main/java/org/apache/camel/spring/spi/TransactionErrorHandler.java @@ -27,7 +27,7 @@ import org.apache.camel.Processor; import org.apache.camel.RuntimeCamelException; import org.apache.camel.processor.errorhandler.RedeliveryErrorHandler; import org.apache.camel.processor.errorhandler.RedeliveryPolicy; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; +import org.apache.camel.processor.errorhandler.ExceptionPolicyStrategy; import org.apache.camel.spi.CamelLogger; import org.apache.camel.support.AsyncProcessorSupport; import org.apache.camel.support.ExchangeHelper; diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/DeadLetterChannel.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DeadLetterChannel.java similarity index 98% rename from core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/DeadLetterChannel.java rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DeadLetterChannel.java index b741bc3..d7b9f00 100644 --- a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/DeadLetterChannel.java +++ b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DeadLetterChannel.java @@ -21,7 +21,6 @@ import java.util.concurrent.ScheduledExecutorService; import org.apache.camel.CamelContext; import org.apache.camel.Predicate; import org.apache.camel.Processor; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; import org.apache.camel.spi.CamelLogger; /** diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/DefaultErrorHandler.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DefaultErrorHandler.java similarity index 97% rename from core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/DefaultErrorHandler.java rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DefaultErrorHandler.java index 187bd6c..d7b3f51 100644 --- a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/DefaultErrorHandler.java +++ b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DefaultErrorHandler.java @@ -21,7 +21,6 @@ import java.util.concurrent.ScheduledExecutorService; import org.apache.camel.CamelContext; import org.apache.camel.Predicate; import org.apache.camel.Processor; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; import org.apache.camel.spi.CamelLogger; /** diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DefaultExceptionPolicyStrategy.java similarity index 75% rename from core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DefaultExceptionPolicyStrategy.java index 3c5b660..f8eebe1 100644 --- a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java +++ b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/DefaultExceptionPolicyStrategy.java @@ -14,10 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.processor.exceptionpolicy; +package org.apache.camel.processor.errorhandler; import java.util.Iterator; -import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; @@ -28,17 +29,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * The default strategy used in Camel to resolve the {@link ExceptionPolicy} that should + * The default strategy used in Camel to resolve the {@link ExceptionPolicyKey} that should * handle the thrown exception. * <p/> * <b>Selection strategy:</b> * <br/>This strategy applies the following rules: * <ul> * <li>Will walk the exception hierarchy from bottom upwards till the thrown exception, meaning that the most outer caused - * by is selected first, ending with the thrown exception itself. The method {@link #createExceptionIterator(Throwable)} + * by is selected first, ending with the thrown exception itself. The method {@link #createExceptionIterable(Throwable)} * provides the Iterator used for the walking.</li> * <li>The exception type must be configured with an Exception that is an instance of the thrown exception, this - * is tested using the {@link #filter(ExceptionPolicy, Class, Throwable)} method. + * is tested using the {@link #filter(ExceptionPolicyKey, Class, Throwable)} method. * By default the filter uses <tt>instanceof</tt> test.</li> * <li>If the exception type has <b>exactly</b> the thrown exception then its selected as its an exact match</li> * <li>Otherwise the type that has an exception that is the closest super of the thrown exception is selected @@ -46,8 +47,8 @@ import org.slf4j.LoggerFactory; * </ul> * <p/> * <b>Fine grained matching:</b> - * <br/> If the {@link ExceptionPolicy} has a when defined with an expression the type is also matches against - * the current exchange using the {@link #matchesWhen(ExceptionPolicy, org.apache.camel.Exchange)} + * <br/> If the {@link ExceptionPolicyKey} has a when defined with an expression the type is also matches against + * the current exchange using the {@link #matchesWhen(ExceptionPolicyKey, org.apache.camel.Exchange)} * method. This can be used to for more fine grained matching, so you can e.g. define multiple sets of * exception types with the same exception class(es) but have a predicate attached to select which to select at runtime. */ @@ -55,27 +56,29 @@ public class DefaultExceptionPolicyStrategy implements ExceptionPolicyStrategy { private static final Logger LOG = LoggerFactory.getLogger(DefaultExceptionPolicyStrategy.class); - public ExceptionPolicy getExceptionPolicy(Map<ExceptionPolicyKey, ExceptionPolicy> exceptionPolicies, - Exchange exchange, Throwable exception) { + @Override + public ExceptionPolicyKey getExceptionPolicy(Set<ExceptionPolicyKey> exceptionPolicies, Exchange exchange, Throwable exception) { - Map<Integer, ExceptionPolicy> candidates = new TreeMap<>(); - Map<ExceptionPolicyKey, ExceptionPolicy> routeScoped = new LinkedHashMap<>(); - Map<ExceptionPolicyKey, ExceptionPolicy> contextScoped = new LinkedHashMap<>(); + Map<Integer, ExceptionPolicyKey> candidates = new TreeMap<>(); + Set<ExceptionPolicyKey> routeScoped = new LinkedHashSet<>(); + Set<ExceptionPolicyKey> contextScoped = new LinkedHashSet<>(); // split policies into route and context scoped initRouteAndContextScopedExceptionPolicies(exceptionPolicies, routeScoped, contextScoped); // at first check route scoped as we prefer them over context scoped // recursive up the tree using the iterator + Iterable<Throwable> throwables = createExceptionIterable(exception); + boolean exactMatch = false; - Iterator<Throwable> it = createExceptionIterator(exception); + Iterator<Throwable> it = throwables.iterator(); while (!exactMatch && it.hasNext()) { // we should stop looking if we have found an exact match exactMatch = findMatchedExceptionPolicy(routeScoped, exchange, it.next(), candidates); } // fallback to check context scoped (only do this if there was no exact match) - it = createExceptionIterator(exception); + it = throwables.iterator(); while (!exactMatch && it.hasNext()) { // we should stop looking if we have found an exact match exactMatch = findMatchedExceptionPolicy(contextScoped, exchange, it.next(), candidates); @@ -93,25 +96,24 @@ public class DefaultExceptionPolicyStrategy implements ExceptionPolicyStrategy { } } - private void initRouteAndContextScopedExceptionPolicies(Map<ExceptionPolicyKey, ExceptionPolicy> exceptionPolicies, - Map<ExceptionPolicyKey, ExceptionPolicy> routeScoped, - Map<ExceptionPolicyKey, ExceptionPolicy> contextScoped) { + private void initRouteAndContextScopedExceptionPolicies(Set<ExceptionPolicyKey> exceptionPolicies, + Set<ExceptionPolicyKey> routeScoped, + Set<ExceptionPolicyKey> contextScoped) { // loop through all the entries and split into route and context scoped - Set<Map.Entry<ExceptionPolicyKey, ExceptionPolicy>> entries = exceptionPolicies.entrySet(); - for (Map.Entry<ExceptionPolicyKey, ExceptionPolicy> entry : entries) { - if (entry.getKey().getRouteId() != null) { - routeScoped.put(entry.getKey(), entry.getValue()); + for (ExceptionPolicyKey entry : exceptionPolicies) { + if (entry.getRouteId() != null) { + routeScoped.add(entry); } else { - contextScoped.put(entry.getKey(), entry.getValue()); + contextScoped.add(entry); } } } - private boolean findMatchedExceptionPolicy(Map<ExceptionPolicyKey, ExceptionPolicy> exceptionPolicies, + private boolean findMatchedExceptionPolicy(Iterable<ExceptionPolicyKey> exceptionPolicies, Exchange exchange, Throwable exception, - Map<Integer, ExceptionPolicy> candidates) { + Map<Integer, ExceptionPolicyKey> candidates) { if (LOG.isTraceEnabled()) { LOG.trace("Finding best suited exception policy for thrown exception {}", exception.getClass().getName()); } @@ -119,22 +121,20 @@ public class DefaultExceptionPolicyStrategy implements ExceptionPolicyStrategy { // the goal is to find the exception with the same/closet inheritance level as the target exception being thrown int targetLevel = getInheritanceLevel(exception.getClass()); // candidate is the best candidate found so far to return - ExceptionPolicy candidate = null; + ExceptionPolicyKey candidate = null; // difference in inheritance level between the current candidate and the thrown exception (target level) int candidateDiff = Integer.MAX_VALUE; // loop through all the entries and find the best candidates to use - Set<Map.Entry<ExceptionPolicyKey, ExceptionPolicy>> entries = exceptionPolicies.entrySet(); - for (Map.Entry<ExceptionPolicyKey, ExceptionPolicy> entry : entries) { - Class<?> clazz = entry.getKey().getExceptionClass(); - ExceptionPolicy type = entry.getValue(); + for (ExceptionPolicyKey type : exceptionPolicies) { + Class<?> clazz = type.getExceptionClass(); // if ExceptionPolicy is route scoped then the current route (Exchange) must match // so we will not pick an ExceptionPolicy from another route - if (exchange != null && exchange.getUnitOfWork() != null && type.isRouteScoped()) { + String typeRoute = type.getRouteId(); + if (exchange != null && exchange.getUnitOfWork() != null && ObjectHelper.isNotEmpty(typeRoute)) { String route = exchange.getUnitOfWork().getRouteContext() != null ? exchange.getUnitOfWork().getRouteContext().getRouteId() : null; - String typeRoute = type.getRouteId(); - if (route != null && typeRoute != null && !route.equals(typeRoute)) { + if (route != null && !route.equals(typeRoute)) { if (LOG.isTraceEnabled()) { LOG.trace("The type is scoped for route: {} however Exchange is at route: {}", typeRoute, route); } @@ -200,7 +200,7 @@ public class DefaultExceptionPolicyStrategy implements ExceptionPolicyStrategy { * @param exception the thrown exception * @return <tt>true</tt> if the to current exception class is a candidate, <tt>false</tt> to skip it. */ - protected boolean filter(ExceptionPolicy type, Class<?> exceptionClass, Throwable exception) { + protected boolean filter(ExceptionPolicyKey type, Class<?> exceptionClass, Throwable exception) { // must be instance of check to ensure that the exceptionClass is one type of the thrown exception return exceptionClass.isInstance(exception); } @@ -218,26 +218,26 @@ public class DefaultExceptionPolicyStrategy implements ExceptionPolicyStrategy { * @param exchange the current {@link Exchange} * @return <tt>true</tt> if matched, <tt>false</tt> otherwise. */ - protected boolean matchesWhen(ExceptionPolicy definition, Exchange exchange) { - if (definition.getOnWhen() == null || definition.getOnWhen() == null) { + protected boolean matchesWhen(ExceptionPolicyKey definition, Exchange exchange) { + if (definition.getWhen() == null) { // if no predicate then it's always a match return true; } - return definition.getOnWhen().matches(exchange); + return definition.getWhen().matches(exchange); } /** * Strategy method creating the iterator to walk the exception in the order Camel should use - * for find the {@link ExceptionPolicy} should be used. + * for find the {@link ExceptionPolicyKey} should be used. * <p/> * The default iterator will walk from the bottom upwards * (the last caused by going upwards to the exception) * * @param exception the exception - * @return the iterator + * @return the list to iterate */ - protected Iterator<Throwable> createExceptionIterator(Throwable exception) { - return ObjectHelper.createExceptionIterator(exception); + protected Iterable<Throwable> createExceptionIterable(Throwable exception) { + return ObjectHelper.createExceptionIterable(exception); } private static int getInheritanceLevel(Class<?> clazz) { diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/ErrorHandlerSupport.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ErrorHandlerSupport.java similarity index 89% rename from core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/ErrorHandlerSupport.java rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ErrorHandlerSupport.java index 5f8a45f..90fce40 100644 --- a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/ErrorHandlerSupport.java +++ b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ErrorHandlerSupport.java @@ -22,10 +22,6 @@ import java.util.Map; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.processor.ErrorHandler; -import org.apache.camel.processor.exceptionpolicy.DefaultExceptionPolicyStrategy; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicy; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyKey; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; import org.apache.camel.support.ChildServiceSupport; /** @@ -44,7 +40,7 @@ public abstract class ErrorHandlerSupport extends ChildServiceSupport implements exceptionPolicies.put(key, policy); } - /** + /**CamelContextHelper * Attempts to find the best suited {@link ExceptionPolicy} to be used for handling the given thrown exception. * * @param exchange the exchange @@ -56,7 +52,8 @@ public abstract class ErrorHandlerSupport extends ChildServiceSupport implements throw new IllegalStateException("The exception policy has not been set"); } - return exceptionPolicy.getExceptionPolicy(exceptionPolicies, exchange, exception); + ExceptionPolicyKey key = exceptionPolicy.getExceptionPolicy(exceptionPolicies.keySet(), exchange, exception); + return key != null ? exceptionPolicies.get(key) : null; } /** diff --git a/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicy.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicy.java new file mode 100644 index 0000000..cbfdc4a --- /dev/null +++ b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicy.java @@ -0,0 +1,261 @@ +/* + * 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.processor.errorhandler; + +import java.util.List; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.LoggingLevel; +import org.apache.camel.Predicate; +import org.apache.camel.Processor; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.support.CamelContextHelper; +import org.apache.camel.util.ObjectHelper; + +public class ExceptionPolicy { + + private String id; + private String routeId; + private boolean useOriginalInMessage; + private boolean hasOutputs; + + private Predicate handledPolicy; + private Predicate continuedPolicy; + private Predicate retryWhilePolicy; + private Processor onRedelivery; + private Processor onExceptionOccurred; + private String redeliveryPolicyRef; + private Map<RedeliveryOption, String> redeliveryPolicy; + private List<String> exceptions; + + public ExceptionPolicy(String id, String routeId, boolean useOriginalInMessage, boolean hasOutputs, Predicate handledPolicy, Predicate continuedPolicy, Predicate retryWhilePolicy, Processor onRedelivery, Processor onExceptionOccurred, String redeliveryPolicyRef, Map<RedeliveryOption, String> redeliveryPolicy, List<String> exceptions) { + this.id = id; + this.routeId = routeId; + this.useOriginalInMessage = useOriginalInMessage; + this.hasOutputs = hasOutputs; + this.handledPolicy = handledPolicy; + this.continuedPolicy = continuedPolicy; + this.retryWhilePolicy = retryWhilePolicy; + this.onRedelivery = onRedelivery; + this.onExceptionOccurred = onExceptionOccurred; + this.redeliveryPolicyRef = redeliveryPolicyRef; + this.redeliveryPolicy = redeliveryPolicy; + this.exceptions = exceptions; + } + + public String getId() { + return id; + } + + public String getRouteId() { + return routeId; + } + + public boolean getUseOriginalInMessage() { + return useOriginalInMessage; + } + + public List<String> getExceptions() { + return exceptions; + } + + public Predicate getHandledPolicy() { + return handledPolicy; + } + + public Predicate getContinuedPolicy() { + return continuedPolicy; + } + + public Predicate getRetryWhilePolicy() { + return retryWhilePolicy; + } + + public Processor getOnRedelivery() { + return onRedelivery; + } + + public Processor getOnExceptionOccurred() { + return onExceptionOccurred; + } + + /** + * Allows an exception handler to create a new redelivery policy for this exception type + * + * @param context the camel context + * @param parentPolicy the current redelivery policy, is newer <tt>null</tt> + * @return a newly created redelivery policy, or return the original policy if no customization is required + * for this exception handler. + */ + public RedeliveryPolicy createRedeliveryPolicy(CamelContext context, RedeliveryPolicy parentPolicy) { + if (redeliveryPolicyRef != null) { + return CamelContextHelper.mandatoryLookup(context, redeliveryPolicyRef, RedeliveryPolicy.class); + } else if (redeliveryPolicy != null) { + return createRedeliveryPolicy(redeliveryPolicy, context, parentPolicy); + } else if (hasOutputs && parentPolicy.getMaximumRedeliveries() != 0) { + // if we have outputs, then do not inherit parent maximumRedeliveries + // as you would have to explicit configure maximumRedeliveries on this onException to use it + // this is the behavior Camel has always had + RedeliveryPolicy answer = parentPolicy.copy(); + answer.setMaximumRedeliveries(0); + return answer; + } else { + return parentPolicy; + } + } + + public boolean determineIfRedeliveryIsEnabled(CamelContext camelContext) throws Exception { + if (redeliveryPolicyRef != null) { + // lookup in registry if ref provided + RedeliveryPolicy policy = CamelContextHelper.mandatoryLookup(camelContext, redeliveryPolicyRef, RedeliveryPolicy.class); + if (policy.getMaximumRedeliveries() != 0) { + // must check for != 0 as (-1 means redeliver forever) + return true; + } + } else if (redeliveryPolicy != null) { + Integer max = CamelContextHelper.parseInteger(camelContext, redeliveryPolicy.get(RedeliveryOption.maximumRedeliveries)); + if (max != null && max != 0) { + // must check for != 0 as (-1 means redeliver forever) + return true; + } + } + + if (retryWhilePolicy != null) { + return true; + } + + return false; + } + + public enum RedeliveryOption { + maximumRedeliveries, + redeliveryDelay, + asyncDelayedRedelivery, + backOffMultiplier, + useExponentialBackOff, + collisionAvoidanceFactor, + useCollisionAvoidance, + maximumRedeliveryDelay, + retriesExhaustedLogLevel, + retryAttemptedLogLevel, + retryAttemptedLogInterval, + logRetryAttempted, + logStackTrace, + logRetryStackTrace, + logHandled, + logNewException, + logContinued, + logExhausted, + logExhaustedMessageHistory, + logExhaustedMessageBody, + disableRedelivery, + delayPattern, + allowRedeliveryWhileStopping, + exchangeFormatterRef; + } + + private static RedeliveryPolicy createRedeliveryPolicy(Map<RedeliveryOption, String> definition, CamelContext context, RedeliveryPolicy parentPolicy) { + RedeliveryPolicy answer; + if (parentPolicy != null) { + answer = parentPolicy.copy(); + } else { + answer = new RedeliveryPolicy(); + } + try { + if (definition.get(RedeliveryOption.maximumRedeliveries) != null) { + answer.setMaximumRedeliveries(CamelContextHelper.parseInteger(context, definition.get(RedeliveryOption.maximumRedeliveries))); + } + if (definition.get(RedeliveryOption.redeliveryDelay) != null) { + answer.setRedeliveryDelay(CamelContextHelper.parseLong(context, definition.get(RedeliveryOption.redeliveryDelay))); + } + if (definition.get(RedeliveryOption.asyncDelayedRedelivery) != null) { + answer.setAsyncDelayedRedelivery(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.asyncDelayedRedelivery))); + } + if (definition.get(RedeliveryOption.retriesExhaustedLogLevel) != null) { + answer.setRetriesExhaustedLogLevel(LoggingLevel.valueOf(definition.get(RedeliveryOption.retriesExhaustedLogLevel))); + } + if (definition.get(RedeliveryOption.retryAttemptedLogLevel) != null) { + answer.setRetryAttemptedLogLevel(LoggingLevel.valueOf(definition.get(RedeliveryOption.retryAttemptedLogLevel))); + } + if (definition.get(RedeliveryOption.retryAttemptedLogInterval) != null) { + answer.setRetryAttemptedLogInterval(CamelContextHelper.parseInteger(context, definition.get(RedeliveryOption.retryAttemptedLogInterval))); + } + if (definition.get(RedeliveryOption.backOffMultiplier) != null) { + answer.setBackOffMultiplier(CamelContextHelper.parseDouble(context, definition.get(RedeliveryOption.backOffMultiplier))); + } + if (definition.get(RedeliveryOption.useExponentialBackOff) != null) { + answer.setUseExponentialBackOff(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.useExponentialBackOff))); + } + if (definition.get(RedeliveryOption.collisionAvoidanceFactor) != null) { + answer.setCollisionAvoidanceFactor(CamelContextHelper.parseDouble(context, definition.get(RedeliveryOption.collisionAvoidanceFactor))); + } + if (definition.get(RedeliveryOption.useCollisionAvoidance) != null) { + answer.setUseCollisionAvoidance(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.useCollisionAvoidance))); + } + if (definition.get(RedeliveryOption.maximumRedeliveryDelay) != null) { + answer.setMaximumRedeliveryDelay(CamelContextHelper.parseLong(context, definition.get(RedeliveryOption.maximumRedeliveryDelay))); + } + if (definition.get(RedeliveryOption.logStackTrace) != null) { + answer.setLogStackTrace(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logStackTrace))); + } + if (definition.get(RedeliveryOption.logRetryStackTrace) != null) { + answer.setLogRetryStackTrace(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logRetryStackTrace))); + } + if (definition.get(RedeliveryOption.logHandled) != null) { + answer.setLogHandled(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logHandled))); + } + if (definition.get(RedeliveryOption.logNewException) != null) { + answer.setLogNewException(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logNewException))); + } + if (definition.get(RedeliveryOption.logContinued) != null) { + answer.setLogContinued(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logContinued))); + } + if (definition.get(RedeliveryOption.logRetryAttempted) != null) { + answer.setLogRetryAttempted(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logRetryAttempted))); + } + if (definition.get(RedeliveryOption.logExhausted) != null) { + answer.setLogExhausted(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logExhausted))); + } + if (definition.get(RedeliveryOption.logExhaustedMessageHistory) != null) { + answer.setLogExhaustedMessageHistory(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logExhaustedMessageHistory))); + } + if (definition.get(RedeliveryOption.logExhaustedMessageBody) != null) { + answer.setLogExhaustedMessageBody(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.logExhaustedMessageBody))); + } + if (definition.get(RedeliveryOption.disableRedelivery) != null) { + if (CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.disableRedelivery))) { + answer.setMaximumRedeliveries(0); + } + } + if (definition.get(RedeliveryOption.delayPattern) != null) { + answer.setDelayPattern(CamelContextHelper.parseText(context, definition.get(RedeliveryOption.delayPattern))); + } + if (definition.get(RedeliveryOption.allowRedeliveryWhileStopping) != null) { + answer.setAllowRedeliveryWhileStopping(CamelContextHelper.parseBoolean(context, definition.get(RedeliveryOption.allowRedeliveryWhileStopping))); + } + if (definition.get(RedeliveryOption.exchangeFormatterRef) != null) { + answer.setExchangeFormatterRef(CamelContextHelper.parseText(context, definition.get(RedeliveryOption.exchangeFormatterRef))); + } + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeCamelException(e); + } + + return answer; + } + +} diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicyKey.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicyKey.java similarity index 95% rename from core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicyKey.java rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicyKey.java index 8efdf59..368e0c2 100644 --- a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicyKey.java +++ b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicyKey.java @@ -14,13 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.processor.exceptionpolicy; +package org.apache.camel.processor.errorhandler; import org.apache.camel.Predicate; /** * Exception policy key is a compound key for storing: - * <b>route id </b> + <b>exception class</b> + <b>when</b> => <b>exception type</b>. + * <b>route id</b> + <b>exception class</b> + <b>when</b> => <b>exception type</b>. * <p/> * This is used by Camel to store the onException types configured that has or has not predicates attached (when). */ diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicyStrategy.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicyStrategy.java similarity index 69% rename from core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicyStrategy.java rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicyStrategy.java index 482085a..7cad346 100644 --- a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicyStrategy.java +++ b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/ExceptionPolicyStrategy.java @@ -14,29 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.processor.exceptionpolicy; +package org.apache.camel.processor.errorhandler; -import java.util.Map; +import java.util.Set; import org.apache.camel.Exchange; /** - * A strategy to determine which {@link ExceptionPolicy} should handle the thrown + * A strategy to determine which {@link ExceptionPolicyKey} should handle the thrown * exception. * - * @see org.apache.camel.processor.exceptionpolicy.DefaultExceptionPolicyStrategy DefaultExceptionPolicy + * @see DefaultExceptionPolicyStrategy DefaultExceptionPolicy */ public interface ExceptionPolicyStrategy { /** - * Resolves the {@link ExceptionPolicy} that should handle the thrown exception. + * Resolves the {@link ExceptionPolicyKey} that should handle the thrown exception. * * @param exceptionPolicies the configured exception policies to resolve from * @param exchange the exchange * @param exception the exception that was thrown * @return the resolved exception type to handle this exception, <tt>null</tt> if none found. */ - ExceptionPolicy getExceptionPolicy(Map<ExceptionPolicyKey, ExceptionPolicy> exceptionPolicies, - Exchange exchange, Throwable exception); + ExceptionPolicyKey getExceptionPolicy(Set<ExceptionPolicyKey> exceptionPolicies, Exchange exchange, Throwable exception); } diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryErrorHandler.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryErrorHandler.java similarity index 99% rename from core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryErrorHandler.java rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryErrorHandler.java index 17d5423..782d8a7 100644 --- a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryErrorHandler.java +++ b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryErrorHandler.java @@ -36,7 +36,6 @@ import org.apache.camel.Navigate; import org.apache.camel.Predicate; import org.apache.camel.Processor; import org.apache.camel.RuntimeCamelException; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicy; import org.apache.camel.spi.AsyncProcessorAwaitManager; import org.apache.camel.spi.CamelLogger; import org.apache.camel.spi.ExchangeFormatter; diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryPolicy.java b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryPolicy.java similarity index 100% rename from core/camel-core/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryPolicy.java rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/RedeliveryPolicy.java diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/package.html b/core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/package.html similarity index 100% rename from core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/package.html rename to core/camel-base/src/main/java/org/apache/camel/processor/errorhandler/package.html diff --git a/core/camel-core/src/main/java/org/apache/camel/builder/ErrorHandlerBuilder.java b/core/camel-core/src/main/java/org/apache/camel/builder/ErrorHandlerBuilder.java index 574c147..e4c87a8 100644 --- a/core/camel-core/src/main/java/org/apache/camel/builder/ErrorHandlerBuilder.java +++ b/core/camel-core/src/main/java/org/apache/camel/builder/ErrorHandlerBuilder.java @@ -21,7 +21,7 @@ import java.util.List; import org.apache.camel.ErrorHandlerFactory; import org.apache.camel.model.OnExceptionDefinition; import org.apache.camel.processor.ErrorHandler; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; +import org.apache.camel.processor.errorhandler.ExceptionPolicyStrategy; import org.apache.camel.spi.RouteContext; /** diff --git a/core/camel-core/src/main/java/org/apache/camel/builder/ErrorHandlerBuilderSupport.java b/core/camel-core/src/main/java/org/apache/camel/builder/ErrorHandlerBuilderSupport.java index 217351d..a0e86e2 100644 --- a/core/camel-core/src/main/java/org/apache/camel/builder/ErrorHandlerBuilderSupport.java +++ b/core/camel-core/src/main/java/org/apache/camel/builder/ErrorHandlerBuilderSupport.java @@ -30,9 +30,10 @@ import org.apache.camel.model.RouteDefinition; import org.apache.camel.processor.ErrorHandler; import org.apache.camel.processor.errorhandler.ErrorHandlerSupport; import org.apache.camel.processor.errorhandler.RedeliveryErrorHandler; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicy; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyKey; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; +import org.apache.camel.processor.errorhandler.ExceptionPolicy; +import org.apache.camel.processor.errorhandler.ExceptionPolicyKey; +import org.apache.camel.processor.errorhandler.ExceptionPolicyStrategy; +import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier; import org.apache.camel.spi.ClassResolver; import org.apache.camel.spi.RouteContext; import org.apache.camel.util.ObjectHelper; @@ -87,7 +88,7 @@ public abstract class ErrorHandlerBuilderSupport implements ErrorHandlerBuilder // load exception classes List<Class<? extends Throwable>> list; - if (exceptionType.getExceptions() != null && !exceptionType.getExceptions().isEmpty()) { + if (ObjectHelper.isNotEmpty(exceptionType.getExceptions())) { list = createExceptionClasses(exceptionType, routeContext.getCamelContext().getClassResolver()); for (Class<? extends Throwable> clazz : list) { String routeId = null; @@ -100,15 +101,15 @@ public abstract class ErrorHandlerBuilderSupport implements ErrorHandlerBuilder } Predicate when = exceptionType.getOnWhen() != null ? exceptionType.getOnWhen().getExpression() : null; ExceptionPolicyKey key = new ExceptionPolicyKey(routeId, clazz, when); - ExceptionPolicy policy = toExceptionPolicy(exceptionType); + ExceptionPolicy policy = toExceptionPolicy(exceptionType, routeContext); handlerSupport.addExceptionPolicy(key, policy); } } } } - protected static ExceptionPolicy toExceptionPolicy(OnExceptionDefinition exceptionType) { - return new ExceptionPolicy(exceptionType); + protected static ExceptionPolicy toExceptionPolicy(OnExceptionDefinition exceptionType, RouteContext routeContext) { + return ErrorHandlerReifier.createExceptionPolicy(exceptionType, routeContext); } protected static List<Class<? extends Throwable>> createExceptionClasses(OnExceptionDefinition exceptionType, ClassResolver resolver) { diff --git a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicy.java b/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicy.java deleted file mode 100644 index cb0cecd..0000000 --- a/core/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/ExceptionPolicy.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.apache.camel.processor.exceptionpolicy; - -import java.util.List; - -import org.apache.camel.CamelContext; -import org.apache.camel.Predicate; -import org.apache.camel.Processor; -import org.apache.camel.model.OnExceptionDefinition; -import org.apache.camel.model.ProcessorDefinitionHelper; -import org.apache.camel.model.RedeliveryPolicyDefinition; -import org.apache.camel.processor.errorhandler.RedeliveryPolicy; -import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier; - -public class ExceptionPolicy { - - private final OnExceptionDefinition def; - - public ExceptionPolicy(OnExceptionDefinition def) { - this.def = def; - } - - public String getId() { - return def.getId(); - } - - public String getRouteId() { - return ProcessorDefinitionHelper.getRouteId(def); - } - - public boolean isRouteScoped() { - return def.getRouteScoped() != null && def.getRouteScoped(); - } - - public Predicate getOnWhen() { - return def.getOnWhen() != null ? def.getOnWhen().getExpression() : null; - } - - public String getRedeliveryPolicyRef() { - return def.getRedeliveryPolicyRef(); - } - - public boolean hasOutputs() { - return def.getOutputs() != null && !def.getOutputs().isEmpty(); - } - - public RedeliveryPolicyDefinition getRedeliveryPolicyType() { - return def.getRedeliveryPolicyType(); - } - - public Predicate getHandledPolicy() { - return def.getHandledPolicy(); - } - - public Predicate getContinuedPolicy() { - return def.getContinuedPolicy(); - } - - public Predicate getRetryWhilePolicy() { - return def.getRetryWhilePolicy(); - } - - public boolean getUseOriginalInMessage() { - return def.getUseOriginalMessagePolicy() != null && def.getUseOriginalMessagePolicy(); - } - - public Processor getOnRedelivery() { - return def.getOnRedelivery(); - } - - public Processor getOnExceptionOccurred() { - return def.getOnExceptionOccurred(); - } - - public List<String> getExceptions() { - return def.getExceptions(); - } - - public boolean determineIfRedeliveryIsEnabled(CamelContext context) throws Exception { - return ErrorHandlerReifier.determineIfRedeliveryIsEnabled(this, context); - } - - public RedeliveryPolicy createRedeliveryPolicy(CamelContext context, RedeliveryPolicy parent) { - return ErrorHandlerReifier.createRedeliveryPolicy(this, context, parent); - } -} diff --git a/core/camel-core/src/main/java/org/apache/camel/reifier/DynamicRouterReifier.java b/core/camel-core/src/main/java/org/apache/camel/reifier/DynamicRouterReifier.java index f030abd..557e291 100644 --- a/core/camel-core/src/main/java/org/apache/camel/reifier/DynamicRouterReifier.java +++ b/core/camel-core/src/main/java/org/apache/camel/reifier/DynamicRouterReifier.java @@ -49,7 +49,7 @@ class DynamicRouterReifier extends ExpressionReifier<DynamicRouterDefinition<?>> // and wrap this in an error handler ErrorHandlerFactory builder = routeContext.getErrorHandlerFactory(); // create error handler (create error handler directly to keep it light weight, - // instead of using ProcessorDefinition.wrapInErrorHandler) + // instead of using ProcessorReifier.wrapInErrorHandler) AsyncProcessor errorHandler = (AsyncProcessor) ErrorHandlerReifier.reifier(builder).createErrorHandler(routeContext, dynamicRouter.newRoutingSlipProcessorForErrorHandler()); dynamicRouter.setErrorHandler(errorHandler); diff --git a/core/camel-core/src/main/java/org/apache/camel/reifier/OnExceptionReifier.java b/core/camel-core/src/main/java/org/apache/camel/reifier/OnExceptionReifier.java index 82e5ec7..98d19f8 100644 --- a/core/camel-core/src/main/java/org/apache/camel/reifier/OnExceptionReifier.java +++ b/core/camel-core/src/main/java/org/apache/camel/reifier/OnExceptionReifier.java @@ -26,7 +26,6 @@ import org.apache.camel.model.OnExceptionDefinition; import org.apache.camel.model.ProcessorDefinition; import org.apache.camel.processor.CatchProcessor; import org.apache.camel.processor.FatalFallbackErrorHandler; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicy; import org.apache.camel.spi.ClassResolver; import org.apache.camel.spi.RouteContext; import org.apache.camel.support.CamelContextHelper; diff --git a/core/camel-core/src/main/java/org/apache/camel/reifier/errorhandler/DefaultErrorHandlerReifier.java b/core/camel-core/src/main/java/org/apache/camel/reifier/errorhandler/DefaultErrorHandlerReifier.java index a262509a..7fcb02b 100644 --- a/core/camel-core/src/main/java/org/apache/camel/reifier/errorhandler/DefaultErrorHandlerReifier.java +++ b/core/camel-core/src/main/java/org/apache/camel/reifier/errorhandler/DefaultErrorHandlerReifier.java @@ -1,21 +1,15 @@ package org.apache.camel.reifier.errorhandler; -import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import org.apache.camel.CamelContext; -import org.apache.camel.Endpoint; import org.apache.camel.ErrorHandlerFactory; -import org.apache.camel.NoSuchEndpointException; import org.apache.camel.Processor; -import org.apache.camel.builder.DeadLetterChannelBuilder; import org.apache.camel.builder.DefaultErrorHandlerBuilder; -import org.apache.camel.processor.errorhandler.DeadLetterChannel; import org.apache.camel.processor.errorhandler.DefaultErrorHandler; import org.apache.camel.spi.ExecutorServiceManager; import org.apache.camel.spi.RouteContext; import org.apache.camel.spi.ThreadPoolProfile; -import org.apache.camel.util.StringHelper; public class DefaultErrorHandlerReifier<T extends DefaultErrorHandlerBuilder> extends ErrorHandlerReifier<T> { diff --git a/core/camel-core/src/main/java/org/apache/camel/reifier/errorhandler/ErrorHandlerReifier.java b/core/camel-core/src/main/java/org/apache/camel/reifier/errorhandler/ErrorHandlerReifier.java index c0b90c4..ca15e64 100644 --- a/core/camel-core/src/main/java/org/apache/camel/reifier/errorhandler/ErrorHandlerReifier.java +++ b/core/camel-core/src/main/java/org/apache/camel/reifier/errorhandler/ErrorHandlerReifier.java @@ -19,8 +19,6 @@ package org.apache.camel.reifier.errorhandler; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ScheduledExecutorService; import java.util.function.Function; import org.apache.camel.CamelContext; @@ -35,12 +33,14 @@ import org.apache.camel.builder.NoErrorHandlerBuilder; import org.apache.camel.model.OnExceptionDefinition; import org.apache.camel.model.RedeliveryPolicyDefinition; import org.apache.camel.processor.ErrorHandler; +import org.apache.camel.processor.errorhandler.ExceptionPolicy; +import org.apache.camel.processor.errorhandler.ExceptionPolicy.RedeliveryOption; import org.apache.camel.processor.errorhandler.ErrorHandlerSupport; import org.apache.camel.processor.errorhandler.RedeliveryErrorHandler; import org.apache.camel.processor.errorhandler.RedeliveryPolicy; -import org.apache.camel.processor.exceptionpolicy.ExceptionPolicy; import org.apache.camel.spi.RouteContext; import org.apache.camel.support.CamelContextHelper; +import org.apache.camel.util.ObjectHelper; public abstract class ErrorHandlerReifier<T extends ErrorHandlerBuilderSupport> { @@ -83,6 +83,60 @@ public abstract class ErrorHandlerReifier<T extends ErrorHandlerBuilderSupport> } } + public static ExceptionPolicy createExceptionPolicy(OnExceptionDefinition def, RouteContext routeContext) { + return new ExceptionPolicy( + def.getId(), + CamelContextHelper.getRouteId(def), + def.getUseOriginalMessagePolicy() != null && def.getUseOriginalMessagePolicy(), + ObjectHelper.isNotEmpty(def.getOutputs()), + def.getHandledPolicy(), + def.getContinuedPolicy(), + def.getRetryWhilePolicy(), + def.getOnRedelivery(), + def.getOnExceptionOccurred(), + def.getRedeliveryPolicyRef(), + getRedeliveryPolicy(def.getRedeliveryPolicyType()), + def.getExceptions()); + } + + private static Map<RedeliveryOption, String> getRedeliveryPolicy(RedeliveryPolicyDefinition definition) { + if (definition == null) { + return null; + } + Map<RedeliveryOption, String> policy = new HashMap<>(); + setoption(policy, RedeliveryOption.maximumRedeliveries, definition.getMaximumRedeliveries()); + setoption(policy, RedeliveryOption.redeliveryDelay, definition.getRedeliveryDelay()); + setoption(policy, RedeliveryOption.asyncDelayedRedelivery, definition.getAsyncDelayedRedelivery()); + setoption(policy, RedeliveryOption.backOffMultiplier, definition.getBackOffMultiplier()); + setoption(policy, RedeliveryOption.useExponentialBackOff, definition.getUseExponentialBackOff()); + setoption(policy, RedeliveryOption.collisionAvoidanceFactor, definition.getCollisionAvoidanceFactor()); + setoption(policy, RedeliveryOption.useCollisionAvoidance, definition.getUseCollisionAvoidance()); + setoption(policy, RedeliveryOption.maximumRedeliveryDelay, definition.getMaximumRedeliveryDelay()); + setoption(policy, RedeliveryOption.retriesExhaustedLogLevel, definition.getRetriesExhaustedLogLevel()); + setoption(policy, RedeliveryOption.retryAttemptedLogLevel, definition.getRetryAttemptedLogLevel()); + setoption(policy, RedeliveryOption.retryAttemptedLogInterval, definition.getRetryAttemptedLogInterval()); + setoption(policy, RedeliveryOption.logRetryAttempted, definition.getLogRetryAttempted()); + setoption(policy, RedeliveryOption.logStackTrace, definition.getLogStackTrace()); + setoption(policy, RedeliveryOption.logRetryStackTrace, definition.getLogRetryStackTrace()); + setoption(policy, RedeliveryOption.logHandled, definition.getLogHandled()); + setoption(policy, RedeliveryOption.logNewException, definition.getLogNewException()); + setoption(policy, RedeliveryOption.logContinued, definition.getLogContinued()); + setoption(policy, RedeliveryOption.logExhausted, definition.getLogExhausted()); + setoption(policy, RedeliveryOption.logExhaustedMessageHistory, definition.getLogExhaustedMessageHistory()); + setoption(policy, RedeliveryOption.logExhaustedMessageBody, definition.getLogExhaustedMessageBody()); + setoption(policy, RedeliveryOption.disableRedelivery, definition.getDisableRedelivery()); + setoption(policy, RedeliveryOption.delayPattern, definition.getDelayPattern()); + setoption(policy, RedeliveryOption.allowRedeliveryWhileStopping, definition.getAllowRedeliveryWhileStopping()); + setoption(policy, RedeliveryOption.exchangeFormatterRef, definition.getExchangeFormatterRef()); + return policy; + } + + private static void setoption(Map<RedeliveryOption, String> policy, RedeliveryOption option, Object value) { + if (value != null) { + policy.put(option, value.toString()); + } + } + /** * Creates the error handler * @@ -206,53 +260,4 @@ public abstract class ErrorHandlerReifier<T extends ErrorHandlerBuilderSupport> return answer; } - /** - * Allows an exception handler to create a new redelivery policy for this exception type - * - * @param definition - * @param context the camel context - * @param parentPolicy the current redelivery policy, is newer <tt>null</tt> - * @return a newly created redelivery policy, or return the original policy if no customization is required - * for this exception handler. - */ - public static RedeliveryPolicy createRedeliveryPolicy(ExceptionPolicy definition, CamelContext context, RedeliveryPolicy parentPolicy) { - if (definition.getRedeliveryPolicyRef() != null) { - return CamelContextHelper.mandatoryLookup(context, definition.getRedeliveryPolicyRef(), RedeliveryPolicy.class); - } else if (definition.getRedeliveryPolicyType() != null) { - return createRedeliveryPolicy(definition.getRedeliveryPolicyType(), context, parentPolicy); - } else if (definition.hasOutputs() && parentPolicy.getMaximumRedeliveries() != 0) { - // if we have outputs, then do not inherit parent maximumRedeliveries - // as you would have to explicit configure maximumRedeliveries on this onException to use it - // this is the behavior Camel has always had - RedeliveryPolicy answer = parentPolicy.copy(); - answer.setMaximumRedeliveries(0); - return answer; - } else { - return parentPolicy; - } - } - - public static boolean determineIfRedeliveryIsEnabled(ExceptionPolicy def, CamelContext camelContext) throws Exception { - String ref = def.getRedeliveryPolicyRef(); - if (ref != null) { - // lookup in registry if ref provided - RedeliveryPolicy policy = CamelContextHelper.mandatoryLookup(camelContext, ref, RedeliveryPolicy.class); - if (policy.getMaximumRedeliveries() != 0) { - // must check for != 0 as (-1 means redeliver forever) - return true; - } - } else if (def.getRedeliveryPolicyType() != null) { - Integer max = CamelContextHelper.parseInteger(camelContext, def.getRedeliveryPolicyType().getMaximumRedeliveries()); - if (max != null && max != 0) { - // must check for != 0 as (-1 means redeliver forever) - return true; - } - } - - if (def.getRetryWhilePolicy() != null) { - return true; - } - - return false; - } } diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/exceptionpolicy/CustomExceptionPolicyStrategyTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/exceptionpolicy/CustomExceptionPolicyStrategyTest.java index f6cb8b8..a969348 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/exceptionpolicy/CustomExceptionPolicyStrategyTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/exceptionpolicy/CustomExceptionPolicyStrategyTest.java @@ -16,7 +16,7 @@ */ package org.apache.camel.processor.exceptionpolicy; -import java.util.Map; +import java.util.Set; import org.apache.camel.CamelException; import org.apache.camel.CamelExchangeException; @@ -25,6 +25,8 @@ import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.processor.errorhandler.ExceptionPolicyKey; +import org.apache.camel.processor.errorhandler.ExceptionPolicyStrategy; import org.junit.Test; /** @@ -42,12 +44,12 @@ public class CustomExceptionPolicyStrategyTest extends ContextTestSupport { // START SNIPPET e2 public static class MyPolicy implements ExceptionPolicyStrategy { - public ExceptionPolicy getExceptionPolicy(Map<ExceptionPolicyKey, ExceptionPolicy> exceptionPolicices, - Exchange exchange, - Throwable exception) { + public ExceptionPolicyKey getExceptionPolicy(Set<ExceptionPolicyKey> exceptionPolicices, + Exchange exchange, + Throwable exception) { // This is just an example that always forces the exception type configured // with MyPolicyException to win. - return exceptionPolicices.get(new ExceptionPolicyKey(null, MyPolicyException.class, null)); + return new ExceptionPolicyKey(null, MyPolicyException.class, null); } } // END SNIPPET e2 diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategyTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategyTest.java index af8ef8a..280e608 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategyTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategyTest.java @@ -29,6 +29,10 @@ import org.apache.camel.ExchangeTimedOutException; import org.apache.camel.RuntimeCamelException; import org.apache.camel.ValidationException; import org.apache.camel.model.OnExceptionDefinition; +import org.apache.camel.processor.errorhandler.DefaultExceptionPolicyStrategy; +import org.apache.camel.processor.errorhandler.ExceptionPolicy; +import org.apache.camel.processor.errorhandler.ExceptionPolicyKey; +import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier; import org.junit.Assert; import org.junit.Test; @@ -43,12 +47,16 @@ public class DefaultExceptionPolicyStrategyTest extends Assert { private ExceptionPolicy type2; private ExceptionPolicy type3; + private ExceptionPolicy exceptionPolicy(Class<? extends Throwable> exceptionClass) { + return ErrorHandlerReifier.createExceptionPolicy(new OnExceptionDefinition(exceptionClass), null); + } + private void setupPolicies() { strategy = new DefaultExceptionPolicyStrategy(); policies = new HashMap<>(); - type1 = new ExceptionPolicy(new OnExceptionDefinition(CamelExchangeException.class)); - type2 = new ExceptionPolicy(new OnExceptionDefinition(Exception.class)); - type3 = new ExceptionPolicy(new OnExceptionDefinition(IOException.class)); + type1 = exceptionPolicy(CamelExchangeException.class); + type2 = exceptionPolicy(Exception.class); + type3 = exceptionPolicy(IOException.class); policies.put(new ExceptionPolicyKey(null, CamelExchangeException.class, null), type1); policies.put(new ExceptionPolicyKey(null, Exception.class, null), type2); policies.put(new ExceptionPolicyKey(null, IOException.class, null), type3); @@ -58,8 +66,8 @@ public class DefaultExceptionPolicyStrategyTest extends Assert { // without the top level exception that can be used as fallback strategy = new DefaultExceptionPolicyStrategy(); policies = new HashMap<>(); - type1 = new ExceptionPolicy(new OnExceptionDefinition(CamelExchangeException.class)); - type3 = new ExceptionPolicy(new OnExceptionDefinition(IOException.class)); + type1 = exceptionPolicy(CamelExchangeException.class); + type3 = exceptionPolicy(IOException.class); policies.put(new ExceptionPolicyKey(null, CamelExchangeException.class, null), type1); policies.put(new ExceptionPolicyKey(null, IOException.class, null), type3); } @@ -67,82 +75,87 @@ public class DefaultExceptionPolicyStrategyTest extends Assert { private void setupPoliciesCausedBy() { strategy = new DefaultExceptionPolicyStrategy(); policies = new HashMap<>(); - type1 = new ExceptionPolicy(new OnExceptionDefinition(FileNotFoundException.class)); - type2 = new ExceptionPolicy(new OnExceptionDefinition(ConnectException.class)); - type3 = new ExceptionPolicy(new OnExceptionDefinition(IOException.class)); + type1 = exceptionPolicy(FileNotFoundException.class); + type2 = exceptionPolicy(ConnectException.class); + type3 = exceptionPolicy(IOException.class); policies.put(new ExceptionPolicyKey(null, FileNotFoundException.class, null), type1); policies.put(new ExceptionPolicyKey(null, IOException.class, null), type2); policies.put(new ExceptionPolicyKey(null, ConnectException.class, null), type3); } + + private ExceptionPolicy findPolicy(Exception exception) { + ExceptionPolicyKey key = strategy.getExceptionPolicy(policies.keySet(), null, exception); + return policies.get(key); + } @Test public void testDirectMatch1() { setupPolicies(); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new CamelExchangeException("", null)); + ExceptionPolicy result = findPolicy(new CamelExchangeException("", null)); assertEquals(type1, result); } @Test public void testDirectMatch2() { setupPolicies(); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new Exception("")); + ExceptionPolicy result = findPolicy(new Exception("")); assertEquals(type2, result); } @Test public void testDirectMatch3() { setupPolicies(); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new IOException("")); + ExceptionPolicy result = findPolicy(new IOException("")); assertEquals(type3, result); } @Test public void testClosetMatch3() { setupPolicies(); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new ConnectException("")); + ExceptionPolicy result = findPolicy(new ConnectException("")); assertEquals(type3, result); - result = strategy.getExceptionPolicy(policies, null, new SocketException("")); + result = findPolicy(new SocketException("")); assertEquals(type3, result); - result = strategy.getExceptionPolicy(policies, null, new FileNotFoundException()); + result = findPolicy(new FileNotFoundException()); assertEquals(type3, result); } @Test public void testClosetMatch2() { setupPolicies(); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new ClassCastException("")); + ExceptionPolicy result = findPolicy(new ClassCastException("")); assertEquals(type2, result); - result = strategy.getExceptionPolicy(policies, null, new NumberFormatException("")); + result = findPolicy(new NumberFormatException("")); assertEquals(type2, result); - result = strategy.getExceptionPolicy(policies, null, new NullPointerException()); + result = findPolicy(new NullPointerException()); assertEquals(type2, result); } @Test public void testClosetMatch1() { setupPolicies(); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new ValidationException(null, "")); + ExceptionPolicy result = findPolicy(new ValidationException(null, "")); assertEquals(type1, result); - result = strategy.getExceptionPolicy(policies, null, new ExchangeTimedOutException(null, 0)); + result = findPolicy(new ExchangeTimedOutException(null, 0)); assertEquals(type1, result); } @Test public void testNoMatch1ThenMatchingJustException() { setupPolicies(); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new AlreadyStoppedException()); + ExceptionPolicy result = findPolicy(new AlreadyStoppedException()); assertEquals(type2, result); } @Test public void testNoMatch1ThenNull() { setupPoliciesNoTopLevelException(); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new AlreadyStoppedException()); + ExceptionPolicy result = findPolicy(new AlreadyStoppedException()); assertNull("Should not find an exception policy to use", result); } @@ -152,7 +165,7 @@ public class DefaultExceptionPolicyStrategyTest extends Assert { IOException ioe = new IOException("Damm"); ioe.initCause(new FileNotFoundException("Somefile not found")); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, ioe); + ExceptionPolicy result = findPolicy(ioe); assertEquals(type1, result); } @@ -162,7 +175,7 @@ public class DefaultExceptionPolicyStrategyTest extends Assert { IOException ioe = new IOException("Damm"); ioe.initCause(new FileNotFoundException("Somefile not found")); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, new RuntimeCamelException(ioe)); + ExceptionPolicy result = findPolicy(new RuntimeCamelException(ioe)); assertEquals(type1, result); } @@ -172,7 +185,7 @@ public class DefaultExceptionPolicyStrategyTest extends Assert { IOException ioe = new IOException("Damm"); ioe.initCause(new ConnectException("Not connected")); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, ioe); + ExceptionPolicy result = findPolicy(ioe); assertEquals(type3, result); } @@ -182,7 +195,7 @@ public class DefaultExceptionPolicyStrategyTest extends Assert { IOException ioe = new IOException("Damm"); ioe.initCause(new MalformedURLException("Bad url")); - ExceptionPolicy result = strategy.getExceptionPolicy(policies, null, ioe); + ExceptionPolicy result = findPolicy(ioe); assertEquals(type2, result); }
