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 }