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    /**
030     * Implements try/catch/finally type processing
031     *
032     * @version $Revision: 752532 $
033     */
034    public class TryProcessor extends ServiceSupport implements Processor {
035        private static final transient Log LOG = LogFactory.getLog(TryProcessor.class);
036    
037        private final Processor tryProcessor;
038        private final List<CatchProcessor> catchClauses;
039        private final Processor finallyProcessor;
040    
041        public TryProcessor(Processor tryProcessor, List<CatchProcessor> catchClauses, Processor finallyProcessor) {
042            this.tryProcessor = tryProcessor;
043            this.catchClauses = catchClauses;
044            this.finallyProcessor = finallyProcessor;
045        }
046    
047        public String toString() {
048            String finallyText = (finallyProcessor == null) ? "" : " Finally {" + finallyProcessor + "}";
049            return "Try {" + tryProcessor + "} " + catchClauses + finallyText;
050        }
051    
052        public void process(Exchange exchange) throws Exception {
053            Exception e;
054    
055            // try processor first
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 && ExchangeHelper.isFailureHandled(exchange)) {
062                    e = null;
063                }
064            } catch (Exception ex) {
065                e = ex;
066                exchange.setException(e);
067            }
068    
069            // handle any exception occured during the try processor
070            try {
071                if (e != null) {
072                    if (LOG.isDebugEnabled()) {
073                        LOG.debug("Caught exception while processing exchange.", e);
074                    }
075                    handleException(exchange, e);
076                }
077            } finally {
078                // and run finally
079                // notice its always executed since we always enter the try block
080                processFinally(exchange);
081            }
082        }
083    
084        protected void doStart() throws Exception {
085            ServiceHelper.startServices(tryProcessor, catchClauses, finallyProcessor);
086        }
087    
088        protected void doStop() throws Exception {
089            ServiceHelper.stopServices(tryProcessor, catchClauses, finallyProcessor);
090        }
091    
092        protected void handleException(Exchange exchange, Throwable e) throws Exception {
093            for (CatchProcessor catchClause : catchClauses) {
094                if (catchClause.catches(e)) {
095                    // lets attach the exception to the exchange
096                    Exchange localExchange = exchange.copy();
097                    
098                    localExchange.setProperty(Exchange.EXCEPTION_CAUGHT, e);
099                    // give the rest of the pipeline another chance
100                    localExchange.setException(null);
101    
102                    // do not catch any exception here, let it propagate up
103                    catchClause.process(localExchange);
104                    localExchange.removeProperty(Exchange.EXCEPTION_CAUGHT);
105                    ExchangeHelper.copyResults(exchange, localExchange);
106                    return;
107                }
108            }
109        }
110    
111        protected void processFinally(Exchange exchange) throws Exception {
112            if (finallyProcessor != null) {
113                Exception lastException = exchange.getException();
114                exchange.setException(null);
115    
116                // do not catch any exception here, let it propagate up
117                finallyProcessor.process(exchange);
118                if (exchange.getException() == null) {
119                    exchange.setException(lastException);
120                }
121            }
122        }
123    }