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.ErrorHandlerFactory;
024import org.apache.camel.NamedNode;
025import org.apache.camel.Predicate;
026import org.apache.camel.Processor;
027import org.apache.camel.RuntimeCamelException;
028import org.apache.camel.model.OnExceptionDefinition;
029import org.apache.camel.model.ProcessorDefinitionHelper;
030import org.apache.camel.model.RouteDefinition;
031import org.apache.camel.processor.ErrorHandler;
032import org.apache.camel.processor.errorhandler.ErrorHandlerSupport;
033import org.apache.camel.processor.errorhandler.ExceptionPolicy;
034import org.apache.camel.processor.errorhandler.ExceptionPolicyKey;
035import org.apache.camel.processor.errorhandler.ExceptionPolicyStrategy;
036import org.apache.camel.processor.errorhandler.RedeliveryErrorHandler;
037import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier;
038import org.apache.camel.spi.ClassResolver;
039import org.apache.camel.spi.RouteContext;
040import org.apache.camel.util.ObjectHelper;
041
042/**
043 * Base class for builders of error handling.
044 */
045public abstract class ErrorHandlerBuilderSupport implements ErrorHandlerBuilder {
046    private ExceptionPolicyStrategy exceptionPolicyStrategy;
047
048    protected void cloneBuilder(ErrorHandlerBuilderSupport other) {
049        other.exceptionPolicyStrategy = exceptionPolicyStrategy;
050    }
051
052    @Override
053    public ErrorHandlerFactory getOrLookupErrorHandlerFactory(RouteContext routeContext) {
054        // only ErrorHandlerRef should override to lookup
055        return this;
056    }
057
058    /**
059     * Configures the other error handler based on this error handler.
060     *
061     * @param routeContext the route context
062     * @param handler the other error handler
063     */
064    public void configure(RouteContext routeContext, ErrorHandler handler) {
065        if (handler instanceof ErrorHandlerSupport) {
066            ErrorHandlerSupport handlerSupport = (ErrorHandlerSupport)handler;
067
068            Set<NamedNode> list = routeContext.getErrorHandlers(this);
069            for (NamedNode exception : list) {
070                addExceptionPolicy(handlerSupport, routeContext, (OnExceptionDefinition)exception);
071            }
072        }
073        if (handler instanceof RedeliveryErrorHandler) {
074            RedeliveryErrorHandler reh = (RedeliveryErrorHandler)handler;
075            boolean original = reh.isUseOriginalMessagePolicy() || reh.isUseOriginalBodyPolicy();
076            if (original) {
077                if (reh.isUseOriginalMessagePolicy() && reh.isUseOriginalBodyPolicy()) {
078                    throw new IllegalArgumentException("Cannot set both useOriginalMessage and useOriginalBody on the error handler");
079                }
080                // ensure allow original is turned on
081                routeContext.setAllowUseOriginalMessage(true);
082            }
083        }
084    }
085
086    public static void addExceptionPolicy(ErrorHandlerSupport handlerSupport, RouteContext routeContext, OnExceptionDefinition exceptionType) {
087        if (routeContext != null) {
088            // add error handler as child service so they get lifecycle handled
089            Processor errorHandler = routeContext.getOnException(exceptionType.getId());
090            handlerSupport.addErrorHandler(errorHandler);
091
092            // load exception classes
093            List<Class<? extends Throwable>> list;
094            if (ObjectHelper.isNotEmpty(exceptionType.getExceptions())) {
095                list = createExceptionClasses(exceptionType, routeContext.getCamelContext().getClassResolver());
096                for (Class<? extends Throwable> clazz : list) {
097                    String routeId = null;
098                    // only get the route id, if the exception type is route
099                    // scoped
100                    if (exceptionType.isRouteScoped()) {
101                        RouteDefinition route = ProcessorDefinitionHelper.getRoute(exceptionType);
102                        if (route != null) {
103                            routeId = route.getId();
104                        }
105                    }
106                    Predicate when = exceptionType.getOnWhen() != null ? exceptionType.getOnWhen().getExpression() : null;
107                    ExceptionPolicyKey key = new ExceptionPolicyKey(routeId, clazz, when);
108                    ExceptionPolicy policy = toExceptionPolicy(exceptionType, routeContext);
109                    handlerSupport.addExceptionPolicy(key, policy);
110                }
111            }
112        }
113    }
114
115    protected static ExceptionPolicy toExceptionPolicy(OnExceptionDefinition exceptionType, RouteContext routeContext) {
116        return ErrorHandlerReifier.createExceptionPolicy(exceptionType, routeContext.getCamelContext());
117    }
118
119    protected static List<Class<? extends Throwable>> createExceptionClasses(OnExceptionDefinition exceptionType, ClassResolver resolver) {
120        List<String> list = exceptionType.getExceptions();
121        List<Class<? extends Throwable>> answer = new ArrayList<>(list.size());
122        for (String name : list) {
123            try {
124                Class<? extends Throwable> type = resolver.resolveMandatoryClass(name, Throwable.class);
125                answer.add(type);
126            } catch (ClassNotFoundException e) {
127                throw RuntimeCamelException.wrapRuntimeCamelException(e);
128            }
129        }
130        return answer;
131    }
132
133    /**
134     * Sets the exception policy to use
135     */
136    public ErrorHandlerBuilderSupport exceptionPolicyStrategy(ExceptionPolicyStrategy exceptionPolicyStrategy) {
137        setExceptionPolicyStrategy(exceptionPolicyStrategy);
138        return this;
139    }
140
141    /**
142     * Gets the exception policy strategy
143     */
144    public ExceptionPolicyStrategy getExceptionPolicyStrategy() {
145        return exceptionPolicyStrategy;
146    }
147
148    /**
149     * Sets the exception policy strategy to use for resolving the
150     * {@link org.apache.camel.model.OnExceptionDefinition} to use for a given
151     * thrown exception
152     *
153     * @param exceptionPolicyStrategy the exception policy strategy
154     */
155    public void setExceptionPolicyStrategy(ExceptionPolicyStrategy exceptionPolicyStrategy) {
156        ObjectHelper.notNull(exceptionPolicyStrategy, "ExceptionPolicyStrategy");
157        this.exceptionPolicyStrategy = exceptionPolicyStrategy;
158    }
159
160}