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 org.apache.camel.AsyncCallback; 020import org.apache.camel.Exchange; 021import org.apache.camel.Processor; 022import org.slf4j.Logger; 023import org.slf4j.LoggerFactory; 024 025/** 026 * An {@link org.apache.camel.processor.ErrorHandler} used as a safe fallback when 027 * processing by other error handlers such as the {@link org.apache.camel.model.OnExceptionDefinition}. 028 * 029 * @version 030 */ 031public class FatalFallbackErrorHandler extends DelegateAsyncProcessor implements ErrorHandler { 032 033 private static final Logger LOG = LoggerFactory.getLogger(FatalFallbackErrorHandler.class); 034 035 private boolean deadLetterChannel; 036 037 public FatalFallbackErrorHandler(Processor processor) { 038 this(processor, false); 039 } 040 041 public FatalFallbackErrorHandler(Processor processor, boolean isDeadLetterChannel) { 042 super(processor); 043 this.deadLetterChannel = isDeadLetterChannel; 044 } 045 046 @Override 047 public boolean process(final Exchange exchange, final AsyncCallback callback) { 048 // support the asynchronous routing engine 049 boolean sync = processor.process(exchange, new AsyncCallback() { 050 public void done(boolean doneSync) { 051 if (exchange.getException() != null) { 052 // an exception occurred during processing onException 053 054 // log detailed error message with as much detail as possible 055 Throwable previous = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class); 056 String msg = "Exception occurred while trying to handle previously thrown exception on exchangeId: " 057 + exchange.getExchangeId() + " using: [" + processor + "]."; 058 if (previous != null) { 059 msg += " The previous and the new exception will be logged in the following."; 060 log(msg); 061 log("\\--> Previous exception on exchangeId: " + exchange.getExchangeId(), previous); 062 log("\\--> New exception on exchangeId: " + exchange.getExchangeId(), exchange.getException()); 063 } else { 064 log(msg); 065 log("\\--> New exception on exchangeId: " + exchange.getExchangeId(), exchange.getException()); 066 } 067 068 // we can propagated that exception to the caught property on the exchange 069 // which will shadow any previously caught exception and cause this new exception 070 // to be visible in the error handler 071 exchange.setProperty(Exchange.EXCEPTION_CAUGHT, exchange.getException()); 072 073 if (deadLetterChannel) { 074 // special for dead letter channel as we want to let it determine what to do, depending how 075 // it has been configured 076 exchange.removeProperty(Exchange.ERRORHANDLER_HANDLED); 077 } else { 078 // mark this exchange as already been error handler handled (just by having this property) 079 // the false value mean the caught exception will be kept on the exchange, causing the 080 // exception to be propagated back to the caller, and to break out routing 081 exchange.setProperty(Exchange.ERRORHANDLER_HANDLED, false); 082 } 083 } 084 callback.done(doneSync); 085 } 086 }); 087 088 return sync; 089 } 090 091 private void log(String message) { 092 log(message, null); 093 } 094 095 private void log(String message, Throwable t) { 096 // when using dead letter channel we only want to log at WARN level 097 if (deadLetterChannel) { 098 if (t != null) { 099 LOG.warn(message, t); 100 } else { 101 LOG.warn(message); 102 } 103 } else { 104 if (t != null) { 105 LOG.error(message, t); 106 } else { 107 LOG.error(message); 108 } 109 } 110 } 111 112 @Override 113 public String toString() { 114 return "FatalFallbackErrorHandler[" + processor + "]"; 115 } 116}