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.model;
018    
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.List;
022    
023    import javax.xml.bind.annotation.XmlAccessType;
024    import javax.xml.bind.annotation.XmlAccessorType;
025    import javax.xml.bind.annotation.XmlElement;
026    import javax.xml.bind.annotation.XmlElementRef;
027    import javax.xml.bind.annotation.XmlRootElement;
028    import javax.xml.bind.annotation.XmlTransient;
029    
030    import org.apache.camel.Expression;
031    import org.apache.camel.Predicate;
032    import org.apache.camel.Processor;
033    import org.apache.camel.Route;
034    import org.apache.camel.builder.ErrorHandlerBuilder;
035    import org.apache.camel.language.constant.ConstantLanguage;
036    import org.apache.camel.processor.CatchProcessor;
037    import org.apache.camel.processor.RedeliveryPolicy;
038    import org.apache.camel.spi.RouteContext;
039    import org.apache.camel.util.ObjectHelper;
040    
041    import static org.apache.camel.builder.PredicateBuilder.toPredicate;
042    
043    /**
044     * Represents an XML <onException/> element
045     *
046     * @version $Revision: 707305 $
047     */
048    @XmlRootElement(name = "onException")
049    @XmlAccessorType(XmlAccessType.FIELD)
050    public class ExceptionType extends ProcessorType<ProcessorType> {
051    
052        @XmlElement(name = "exception")
053        private List<String> exceptions = new ArrayList<String>();
054        @XmlElement(name = "redeliveryPolicy", required = false)
055        private RedeliveryPolicyType redeliveryPolicy;
056        @XmlElement(name = "handled", required = false)
057        private ExpressionSubElementType handled;
058        @XmlElementRef
059        private List<ProcessorType<?>> outputs = new ArrayList<ProcessorType<?>>();
060        @XmlTransient
061        private List<Class> exceptionClasses;
062        @XmlTransient
063        private Processor errorHandler;
064        @XmlTransient
065        private Predicate handledPolicy;
066    
067        public ExceptionType() {
068        }
069    
070        public ExceptionType(List<Class> exceptionClasses) {
071            this.exceptionClasses = exceptionClasses;
072        }
073    
074        public ExceptionType(Class exceptionType) {
075            exceptionClasses = new ArrayList<Class>();
076            exceptionClasses.add(exceptionType);
077        }
078    
079        @Override
080        public String toString() {
081            return "Exception[" + getExceptionClasses() + " -> " + getOutputs() + "]";
082        }
083        
084        /**
085         * Catches an exception type.
086         */
087        @Override
088        public ExceptionType onException(Class exceptionType) {
089            getExceptionClasses().add(exceptionType);
090            return this;
091        }
092        
093        /**
094         * Allows an exception handler to create a new redelivery policy for this exception type
095         * @param parentPolicy the current redelivery policy
096         * @return a newly created redelivery policy, or return the original policy if no customization is required
097         * for this exception handler.
098         */
099        public RedeliveryPolicy createRedeliveryPolicy(RedeliveryPolicy parentPolicy) {
100            if (redeliveryPolicy != null) {
101                return redeliveryPolicy.createRedeliveryPolicy(parentPolicy);
102            } else if (errorHandler != null) {
103                // lets create a new error handler that has no retries
104                RedeliveryPolicy answer = parentPolicy.copy();
105                answer.setMaximumRedeliveries(0);
106                return answer;
107            }
108            return parentPolicy;
109        }
110    
111        public void addRoutes(RouteContext routeContext, Collection<Route> routes) throws Exception {
112            setHandledFromExpressionType(routeContext);
113            // lets attach a processor to an error handler
114            errorHandler = routeContext.createProcessor(this);
115            ErrorHandlerBuilder builder = routeContext.getRoute().getErrorHandlerBuilder();
116            builder.addErrorHandlers(this);
117        }
118    
119        @Override
120        public CatchProcessor createProcessor(RouteContext routeContext) throws Exception {
121            Processor childProcessor = routeContext.createProcessor(this);
122            return new CatchProcessor(getExceptionClasses(), childProcessor);
123        }
124    
125    
126        // Fluent API
127        //-------------------------------------------------------------------------
128        public ExceptionType handled(boolean handled) {
129            ConstantLanguage constant = new ConstantLanguage();
130            return handled(constant.createPredicate(Boolean.toString(handled)));
131        }
132        
133        public ExceptionType handled(Predicate handled) {
134            setHandledPolicy(handled);
135            return this;
136        }
137        
138        public ExceptionType handled(Expression handled) {
139            setHandledPolicy(toPredicate(handled));
140            return this;
141        }
142    
143        public ExceptionType backOffMultiplier(double backOffMultiplier) {
144            getOrCreateRedeliveryPolicy().backOffMultiplier(backOffMultiplier);
145            return this;
146        }
147    
148        public ExceptionType collisionAvoidanceFactor(double collisionAvoidanceFactor) {
149            getOrCreateRedeliveryPolicy().collisionAvoidanceFactor(collisionAvoidanceFactor);
150            return this;
151        }
152    
153        public ExceptionType collisionAvoidancePercent(short collisionAvoidancePercent) {
154            getOrCreateRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent);
155            return this;
156        }
157    
158        public ExceptionType initialRedeliveryDelay(long initialRedeliveryDelay) {
159            getOrCreateRedeliveryPolicy().initialRedeliveryDelay(initialRedeliveryDelay);
160            return this;
161        }
162    
163        public ExceptionType maximumRedeliveries(int maximumRedeliveries) {
164            getOrCreateRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries);
165            return this;
166        }
167    
168        public ExceptionType useCollisionAvoidance() {
169            getOrCreateRedeliveryPolicy().useCollisionAvoidance();
170            return this;
171        }
172    
173        public ExceptionType useExponentialBackOff() {
174            getOrCreateRedeliveryPolicy().useExponentialBackOff();
175            return this;
176        }
177    
178        public ExceptionType maximumRedeliveryDelay(long maximumRedeliveryDelay) {
179            getOrCreateRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay);
180            return this;
181        }
182    
183        // Properties
184        //-------------------------------------------------------------------------
185        public List<ProcessorType<?>> getOutputs() {
186            return outputs;
187        }
188    
189        public void setOutputs(List<ProcessorType<?>> outputs) {
190            this.outputs = outputs;
191        }
192    
193        public List<Class> getExceptionClasses() {
194            if (exceptionClasses == null) {
195                exceptionClasses = createExceptionClasses();
196            }
197            return exceptionClasses;
198        }
199    
200        public void setExceptionClasses(List<Class> exceptionClasses) {
201            this.exceptionClasses = exceptionClasses;
202        }
203    
204        public List<String> getExceptions() {
205            return exceptions;
206        }
207    
208        public void setExceptions(List<String> exceptions) {
209            this.exceptions = exceptions;
210        }
211    
212        public Processor getErrorHandler() {
213            return errorHandler;
214        }
215    
216        public RedeliveryPolicyType getRedeliveryPolicy() {
217            return redeliveryPolicy;
218        }
219    
220        public void setRedeliveryPolicy(RedeliveryPolicyType redeliveryPolicy) {
221            this.redeliveryPolicy = redeliveryPolicy;
222        }
223    
224        public Predicate getHandledPolicy() {
225            return handledPolicy;
226        }
227    
228        public void setHandled(ExpressionSubElementType handled) {
229            this.handled = handled;
230        }
231    
232        public ExpressionSubElementType getHandled() {
233            return handled;
234        }    
235        
236        private void setHandledFromExpressionType(RouteContext routeContext) {
237            if (getHandled() != null && handledPolicy == null && routeContext != null) {  
238                handled(getHandled().createPredicate(routeContext));
239            }
240        }
241    
242        public void setHandledPolicy(Predicate handledPolicy) {
243            this.handledPolicy = handledPolicy;
244        }
245    
246        // Implementation methods
247        //-------------------------------------------------------------------------
248        protected RedeliveryPolicyType getOrCreateRedeliveryPolicy() {
249            if (redeliveryPolicy == null) {
250                redeliveryPolicy = new RedeliveryPolicyType();
251            }
252            return redeliveryPolicy;
253        }
254    
255        protected List<Class> createExceptionClasses() {
256            List<String> list = getExceptions();
257            List<Class> answer = new ArrayList<Class>(list.size());
258            for (String name : list) {
259                Class type = ObjectHelper.loadClass(name, getClass().getClassLoader());
260                answer.add(type);
261            }
262            return answer;
263        }
264    }