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 }