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;
018    
019    import java.util.List;
020    
021    import org.apache.camel.Exchange;
022    import org.apache.camel.Processor;
023    import org.apache.camel.impl.ServiceSupport;
024    import org.apache.camel.util.ExchangeHelper;
025    import org.apache.camel.util.ServiceHelper;
026    import org.apache.commons.logging.Log;
027    import org.apache.commons.logging.LogFactory;
028    
029    import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException;
030    
031    /**
032     * Implements try/catch/finally type processing
033     *
034     * @version $Revision: 51563 $
035     */
036    public class TryProcessor extends ServiceSupport implements Processor {
037        private static final transient Log LOG = LogFactory.getLog(TryProcessor.class);
038    
039        private final Processor tryProcessor;
040        private final List<CatchProcessor> catchClauses;
041        private final Processor finallyProcessor;
042    
043        public TryProcessor(Processor tryProcessor, List<CatchProcessor> catchClauses, Processor finallyProcessor) {
044            this.tryProcessor = tryProcessor;
045            this.catchClauses = catchClauses;
046            this.finallyProcessor = finallyProcessor;
047        }
048    
049        public String toString() {
050            String finallyText = (finallyProcessor == null) ? "" : " Finally {" + finallyProcessor + "}";
051            return "Try {" + tryProcessor + "} " + catchClauses + finallyText;
052        }
053    
054        public void process(Exchange exchange) throws Exception {
055            Throwable e = null;
056            try {
057                tryProcessor.process(exchange);
058                e = exchange.getException();
059    
060                // Ignore it if it was handled by the dead letter channel.
061                if (e != null && DeadLetterChannel.isFailureHandled(exchange)) {
062                    e = null;
063                }
064            } catch (Throwable ex) {
065                e = ex;
066                exchange.setException(e);
067            }
068    
069            Exception unexpected = null;
070            try {
071                if (e != null) {
072                    LOG.info("Caught exception while processing exchange.", e);
073                    handleException(exchange, e);
074                }
075            } catch (Exception ex) {
076                unexpected = ex;
077            } catch (Throwable ex) {
078                unexpected = wrapRuntimeCamelException(ex);
079            } finally {
080                try {
081                    processFinally(exchange);
082                } catch (Exception ex) {
083                    unexpected = ex;
084                } catch (Throwable ex) {
085                    unexpected = wrapRuntimeCamelException(ex);
086                }
087                if (unexpected != null) {
088                    LOG.warn("Caught exception inside processFinally clause.", unexpected);
089                    throw unexpected;
090                }
091            }
092    
093            if (unexpected != null) {
094                LOG.warn("Caught exception inside handle clause.", unexpected);
095                throw unexpected;
096            }
097        }
098    
099        protected void doStart() throws Exception {
100            ServiceHelper.startServices(tryProcessor, catchClauses, finallyProcessor);
101        }
102    
103        protected void doStop() throws Exception {
104            ServiceHelper.stopServices(tryProcessor, catchClauses, finallyProcessor);
105        }
106    
107        protected void handleException(Exchange exchange, Throwable e) throws Throwable {
108            for (CatchProcessor catchClause : catchClauses) {
109                if (catchClause.catches(e)) {
110                    // lets attach the exception to the exchange
111                    Exchange localExchange = exchange.copy();
112                    localExchange.getIn().setHeader("caught.exception", e);
113                    // give the rest of the pipeline another chance
114                    localExchange.setException(null);
115    
116                    // do not catch any exception here, let it propagate up
117                    catchClause.process(localExchange);
118                    localExchange.getIn().removeHeader("caught.exception");
119                    ExchangeHelper.copyResults(exchange, localExchange);
120                    return;
121                }
122            }
123        }
124    
125        protected void processFinally(Exchange exchange) throws Throwable {
126            if (finallyProcessor != null) {
127                Throwable lastException = exchange.getException();
128                exchange.setException(null);
129    
130                // do not catch any exception here, let it propagate up
131                finallyProcessor.process(exchange);
132                if (exchange.getException() == null) {
133                    exchange.setException(lastException);
134                }
135            }
136        }
137    }