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