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.Iterator;
020    import java.util.List;
021    
022    import org.apache.camel.Exchange;
023    import org.apache.camel.Predicate;
024    import org.apache.camel.Processor;
025    import org.apache.camel.util.ObjectHelper;
026    
027    /**
028     * A processor which catches exceptions.
029     *
030     * @version $Revision: 881198 $
031     */
032    public class CatchProcessor extends DelegateProcessor implements Traceable {
033        private final List<Class> exceptions;
034        private final Predicate onWhen;
035        private final Predicate handled;
036    
037        public CatchProcessor(List<Class> exceptions, Processor processor, Predicate onWhen, Predicate handled) {
038            super(processor);
039            this.exceptions = exceptions;
040            this.onWhen = onWhen;
041            this.handled = handled;
042        }
043    
044        @Override
045        public String toString() {
046            return "Catch[" + exceptions + " -> " + getProcessor() + "]";
047        }
048    
049        public String getTraceLabel() {
050            return "catch";
051        }
052    
053        /**
054         * Returns with the exception that is caught by this processor.
055         * 
056         * This method traverses exception causes, so sometimes the exception
057         * returned from this method might be one of causes of the parameter
058         * passed.
059         *
060         * @param exchange  the current exchange
061         * @param exception the thrown exception
062         * @return Throwable that this processor catches. <tt>null</tt> if nothing matches.
063         */
064        public Throwable catches(Exchange exchange, Throwable exception) {
065            // use the exception iterator to walk the caused by hierarchy
066            Iterator<Throwable> it = ObjectHelper.createExceptionIterator(exception);
067            while (it.hasNext()) {
068                Throwable e = it.next();
069                // see if we catch this type
070                for (Class<?> type : exceptions) {
071                    if (type.isInstance(e) && matchesWhen(exchange)) {
072                        return e;
073                    }
074                }
075            }
076    
077            // not found
078            return null;
079        }
080    
081    
082        /**
083         * Whether this catch processor handles the exception it have caught
084         *
085         * @param exchange  the current exchange
086         * @return <tt>true</tt> if this processor handles it, <tt>false</tt> otherwise.
087         */
088        public boolean handles(Exchange exchange) {
089            if (handled == null) {
090                // handle by default
091                return true;
092            }
093    
094            return handled.matches(exchange);
095        }
096    
097        public List<Class> getExceptions() {
098            return exceptions;
099        }
100    
101        /**
102         * Strategy method for matching the exception type with the current exchange.
103         * <p/>
104         * This default implementation will match as:
105         * <ul>
106         * <li>Always true if no when predicate on the exception type
107         * <li>Otherwise the when predicate is matches against the current exchange
108         * </ul>
109         *
110         * @param exchange the current {@link org.apache.camel.Exchange}
111         * @return <tt>true</tt> if matched, <tt>false</tt> otherwise.
112         */
113        protected boolean matchesWhen(Exchange exchange) {
114            if (onWhen == null) {
115                // if no predicate then it's always a match
116                return true;
117            }
118            return onWhen.matches(exchange);
119        }
120    }