001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.builder;
018
019import java.util.ArrayList;
020import java.util.List;
021import java.util.Set;
022
023import org.apache.camel.NamedNode;
024import org.apache.camel.Predicate;
025import org.apache.camel.Processor;
026import org.apache.camel.RuntimeCamelException;
027import org.apache.camel.model.OnExceptionDefinition;
028import org.apache.camel.model.ProcessorDefinitionHelper;
029import org.apache.camel.model.RouteDefinition;
030import org.apache.camel.processor.ErrorHandler;
031import org.apache.camel.processor.errorhandler.ErrorHandlerSupport;
032import org.apache.camel.processor.errorhandler.ExceptionPolicy;
033import org.apache.camel.processor.errorhandler.ExceptionPolicyKey;
034import org.apache.camel.processor.errorhandler.ExceptionPolicyStrategy;
035import org.apache.camel.processor.errorhandler.RedeliveryErrorHandler;
036import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier;
037import org.apache.camel.spi.ClassResolver;
038import org.apache.camel.spi.RouteContext;
039import org.apache.camel.util.ObjectHelper;
040
041/**
042 * Base class for builders of error handling.
043 */
044public abstract class ErrorHandlerBuilderSupport implements ErrorHandlerBuilder {
045    private ExceptionPolicyStrategy exceptionPolicyStrategy;
046
047    protected void cloneBuilder(ErrorHandlerBuilderSupport other) {
048        other.exceptionPolicyStrategy = exceptionPolicyStrategy;
049    }
050
051    /**
052     * Configures the other error handler based on this error handler.
053     *
054     * @param routeContext the route context
055     * @param handler the other error handler
056     */
057    public void configure(RouteContext routeContext, ErrorHandler handler) {
058        if (handler instanceof ErrorHandlerSupport) {
059            ErrorHandlerSupport handlerSupport = (ErrorHandlerSupport)handler;
060
061            Set<NamedNode> list = routeContext.getErrorHandlers(this);
062            for (NamedNode exception : list) {
063                addExceptionPolicy(handlerSupport, routeContext, (OnExceptionDefinition)exception);
064            }
065        }
066        if (handler instanceof RedeliveryErrorHandler) {
067            RedeliveryErrorHandler reh = (RedeliveryErrorHandler)handler;
068            boolean original = reh.isUseOriginalMessagePolicy() || reh.isUseOriginalBodyPolicy();
069            if (original) {
070                if (reh.isUseOriginalMessagePolicy() && reh.isUseOriginalBodyPolicy()) {
071                    throw new IllegalArgumentException("Cannot set both useOriginalMessage and useOriginalBody on the error handler");
072                }
073                // ensure allow original is turned on
074                routeContext.setAllowUseOriginalMessage(true);
075            }
076        }
077    }
078
079    public static void addExceptionPolicy(ErrorHandlerSupport handlerSupport, RouteContext routeContext, OnExceptionDefinition exceptionType) {
080        if (routeContext != null) {
081            // add error handler as child service so they get lifecycle handled
082            Processor errorHandler = routeContext.getOnException(exceptionType.getId());
083            handlerSupport.addErrorHandler(errorHandler);
084
085            // load exception classes
086            List<Class<? extends Throwable>> list;
087            if (ObjectHelper.isNotEmpty(exceptionType.getExceptions())) {
088                list = createExceptionClasses(exceptionType, routeContext.getCamelContext().getClassResolver());
089                for (Class<? extends Throwable> clazz : list) {
090                    String routeId = null;
091                    // only get the route id, if the exception type is route
092                    // scoped
093                    if (exceptionType.isRouteScoped()) {
094                        RouteDefinition route = ProcessorDefinitionHelper.getRoute(exceptionType);
095                        if (route != null) {
096                            routeId = route.getId();
097                        }
098                    }
099                    Predicate when = exceptionType.getOnWhen() != null ? exceptionType.getOnWhen().getExpression() : null;
100                    ExceptionPolicyKey key = new ExceptionPolicyKey(routeId, clazz, when);
101                    ExceptionPolicy policy = toExceptionPolicy(exceptionType, routeContext);
102                    handlerSupport.addExceptionPolicy(key, policy);
103                }
104            }
105        }
106    }
107
108    protected static ExceptionPolicy toExceptionPolicy(OnExceptionDefinition exceptionType, RouteContext routeContext) {
109        return ErrorHandlerReifier.createExceptionPolicy(exceptionType, routeContext);
110    }
111
112    protected static List<Class<? extends Throwable>> createExceptionClasses(OnExceptionDefinition exceptionType, ClassResolver resolver) {
113        List<String> list = exceptionType.getExceptions();
114        List<Class<? extends Throwable>> answer = new ArrayList<>(list.size());
115        for (String name : list) {
116            try {
117                Class<? extends Throwable> type = resolver.resolveMandatoryClass(name, Throwable.class);
118                answer.add(type);
119            } catch (ClassNotFoundException e) {
120                throw RuntimeCamelException.wrapRuntimeCamelException(e);
121            }
122        }
123        return answer;
124    }
125
126    /**
127     * Sets the exception policy to use
128     */
129    public ErrorHandlerBuilderSupport exceptionPolicyStrategy(ExceptionPolicyStrategy exceptionPolicyStrategy) {
130        setExceptionPolicyStrategy(exceptionPolicyStrategy);
131        return this;
132    }
133
134    /**
135     * Gets the exception policy strategy
136     */
137    public ExceptionPolicyStrategy getExceptionPolicyStrategy() {
138        return exceptionPolicyStrategy;
139    }
140
141    /**
142     * Sets the exception policy strategy to use for resolving the
143     * {@link org.apache.camel.model.OnExceptionDefinition} to use for a given
144     * thrown exception
145     *
146     * @param exceptionPolicyStrategy the exception policy strategy
147     */
148    public void setExceptionPolicyStrategy(ExceptionPolicyStrategy exceptionPolicyStrategy) {
149        ObjectHelper.notNull(exceptionPolicyStrategy, "ExceptionPolicyStrategy");
150        this.exceptionPolicyStrategy = exceptionPolicyStrategy;
151    }
152
153}