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     */
017    package org.apache.camel.processor.exceptionpolicy;
018    
019    import java.util.Map;
020    import java.util.Set;
021    
022    import org.apache.camel.Exchange;
023    import org.apache.camel.model.ExceptionType;
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    
027    /**
028     * The default strategy used in Camel to resolve the {@link org.apache.camel.model.ExceptionType} that should
029     * handle the thrown exception.
030     * <p/>
031     * This strategy applies the following rules:
032     * <ul>
033     *   <li>The exception type must be configured with an Exception that is an instance of the thrown exception</li>
034     *   <li>If the exception type has exactly the thrown exception then its selected</li>
035     *   <li>Otherwise the type that has an exception that is super of the thrown exception is selected
036     *       (recurring up the exception hierarchy)
037     *  </ul>
038     */
039    public class DefaultExceptionPolicyStrategy implements ExceptionPolicyStrategy {
040    
041        private static final transient Log LOG = LogFactory.getLog(DefaultExceptionPolicyStrategy.class);
042    
043        public ExceptionType getExceptionPolicy(Map<Class, ExceptionType> exceptionPolicices, Exchange exchange,
044                                                Throwable exception) {
045            if (LOG.isDebugEnabled()) {
046                LOG.debug("Finding best suited exception policy for thrown exception " + exception.getClass().getName());
047            }
048    
049            // the goal is to find the exception with the same/closet inheritance level as the target exception being thrown
050            int targetLevel = getInheritanceLevel(exception.getClass());
051            // candidate is the best candidate found so far to return
052            ExceptionType candidate = null;
053            // difference in inheritance level between the current candidate and the thrown exception (target level)
054            int candidateDiff = Integer.MAX_VALUE;
055    
056            // loop through all the entries and find the best candidates to use
057            Set<Map.Entry<Class, ExceptionType>> entries = exceptionPolicices.entrySet();
058            for (Map.Entry<Class, ExceptionType> entry : entries) {
059                Class clazz = entry.getKey();
060                ExceptionType type = entry.getValue();
061    
062                // must be instance of check to ensure that the clazz is one type of the thrown exception
063                if (clazz.isInstance(exception)) {
064    
065                    // exact match
066                    if (clazz.equals(exception.getClass())) {
067                        candidate = type;
068                        break;
069                    }
070    
071                    // not an exact match so find the best candidate
072                    int level = getInheritanceLevel(clazz);
073                    int diff = targetLevel - level;
074    
075                    if (diff < candidateDiff) {
076                        // replace with a much better candidate
077                        candidate = type;
078                        candidateDiff = diff;
079                    }
080                }
081            }
082    
083            if (LOG.isDebugEnabled()) {
084                if (candidate != null) {
085                    LOG.debug("Using " + candidate + " as the exception policy");
086                } else {
087                    LOG.debug("No candidate found to be used as exception policy");
088                }
089            }
090    
091            return candidate;
092        }
093    
094        private static int getInheritanceLevel(Class clazz) {
095            if (clazz == null || "java.lang.Object".equals(clazz.getName())) {
096                return 0;
097            }
098            return 1 + getInheritanceLevel(clazz.getSuperclass());
099        }
100    
101    }