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.processor;
018
019import java.util.ArrayList;
020import java.util.LinkedHashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.camel.Exchange;
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.exceptionpolicy.DefaultExceptionPolicyStrategy;
031import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyKey;
032import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy;
033import org.apache.camel.spi.ClassResolver;
034import org.apache.camel.spi.RouteContext;
035import org.apache.camel.support.ChildServiceSupport;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039/**
040 * Support class for {@link ErrorHandler} implementations.
041 *
042 * @version 
043 */
044public abstract class ErrorHandlerSupport extends ChildServiceSupport implements ErrorHandler {
045
046    protected final Logger log = LoggerFactory.getLogger(getClass());
047
048    protected final Map<ExceptionPolicyKey, OnExceptionDefinition> exceptionPolicies = new LinkedHashMap<>();
049    protected ExceptionPolicyStrategy exceptionPolicy = createDefaultExceptionPolicyStrategy();
050
051    public void addExceptionPolicy(RouteContext routeContext, OnExceptionDefinition exceptionType) {
052        if (routeContext != null) {
053            // add error handler as child service so they get lifecycle handled
054            Processor errorHandler = exceptionType.getErrorHandler(routeContext.getRoute().getId());
055            if (errorHandler != null) {
056                addChildService(errorHandler);
057            }
058
059            List<Class<? extends Throwable>> list = null;
060            if (exceptionType.getExceptions() != null && !exceptionType.getExceptions().isEmpty()) {
061                list = createExceptionClasses(exceptionType, routeContext.getCamelContext().getClassResolver());
062                for (Class<? extends Throwable> clazz : list) {
063                    String routeId = null;
064                    // only get the route id, if the exception type is route scoped
065                    if (exceptionType.isRouteScoped()) {
066                        RouteDefinition route = ProcessorDefinitionHelper.getRoute(exceptionType);
067                        if (route != null) {
068                            routeId = route.getId();
069                        }
070                    }
071                    ExceptionPolicyKey key = new ExceptionPolicyKey(routeId, clazz, exceptionType.getOnWhen());
072                    exceptionPolicies.put(key, exceptionType);
073                }
074            }
075        }
076    }
077
078    protected List<Class<? extends Throwable>> createExceptionClasses(OnExceptionDefinition exceptionType, ClassResolver resolver) {
079        List<String> list = exceptionType.getExceptions();
080        List<Class<? extends Throwable>> answer = new ArrayList<>(list.size());
081        for (String name : list) {
082            try {
083                Class<? extends Throwable> type = resolver.resolveMandatoryClass(name, Throwable.class);
084                answer.add(type);
085            } catch (ClassNotFoundException e) {
086                throw new RuntimeCamelException(e);
087            }
088        }
089        return answer;
090    }
091
092    /**
093     * Attempts to find the best suited {@link OnExceptionDefinition} to be used for handling the given thrown exception.
094     *
095     * @param exchange  the exchange
096     * @param exception the exception that was thrown
097     * @return the best exception type to handle this exception, <tt>null</tt> if none found.
098     */
099    protected OnExceptionDefinition getExceptionPolicy(Exchange exchange, Throwable exception) {
100        if (exceptionPolicy == null) {
101            throw new IllegalStateException("The exception policy has not been set");
102        }
103
104        return exceptionPolicy.getExceptionPolicy(exceptionPolicies, exchange, exception);
105    }
106
107    /**
108     * Sets the strategy to use for resolving the {@link OnExceptionDefinition} to use
109     * for handling thrown exceptions.
110     */
111    public void setExceptionPolicy(ExceptionPolicyStrategy exceptionPolicy) {
112        if (exceptionPolicy != null) {
113            this.exceptionPolicy = exceptionPolicy;
114        }
115    }
116
117    /**
118     * Creates the default exception policy strategy to use.
119     */
120    public static ExceptionPolicyStrategy createDefaultExceptionPolicyStrategy() {
121        return new DefaultExceptionPolicyStrategy();
122    }
123
124    /**
125     * Whether this error handler supports transacted exchanges or not.
126     */
127    public abstract boolean supportTransacted();
128
129    /**
130     * Whether this error handler handles exhausted errors by moving the exchange to a dead letter channel.
131     */
132    public boolean isDeadLetterChannel() {
133        return false;
134    }
135
136    /**
137     * Gets the output
138     */
139    public abstract Processor getOutput();
140
141}