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.XmlAttribute;
026 import javax.xml.bind.annotation.XmlElement;
027 import javax.xml.bind.annotation.XmlElementRef;
028 import javax.xml.bind.annotation.XmlRootElement;
029 import javax.xml.bind.annotation.XmlTransient;
030
031 import org.apache.camel.CamelContext;
032 import org.apache.camel.Expression;
033 import org.apache.camel.LoggingLevel;
034 import org.apache.camel.Predicate;
035 import org.apache.camel.Processor;
036 import org.apache.camel.Route;
037 import org.apache.camel.builder.ErrorHandlerBuilder;
038 import org.apache.camel.builder.ExpressionClause;
039 import org.apache.camel.language.constant.ConstantLanguage;
040 import org.apache.camel.processor.CatchProcessor;
041 import org.apache.camel.processor.RedeliveryPolicy;
042 import org.apache.camel.spi.RouteContext;
043 import org.apache.camel.util.ObjectHelper;
044
045 import static org.apache.camel.builder.PredicateBuilder.toPredicate;
046
047 /**
048 * Represents an XML <onException/> element
049 *
050 * @version $Revision: 751373 $
051 */
052 @XmlRootElement(name = "onException")
053 @XmlAccessorType(XmlAccessType.FIELD)
054 public class OnExceptionDefinition extends ProcessorDefinition<ProcessorDefinition> {
055
056 @XmlElement(name = "exception")
057 private List<String> exceptions = new ArrayList<String>();
058 @XmlElement(name = "onWhen", required = false)
059 private WhenDefinition onWhen;
060 @XmlElement(name = "retryUntil", required = false)
061 private ExpressionSubElementDefinition retryUntil;
062 @XmlElement(name = "redeliveryPolicy", required = false)
063 private RedeliveryPolicyDefinition redeliveryPolicy;
064 @XmlElement(name = "handled", required = false)
065 private ExpressionSubElementDefinition handled;
066 @XmlAttribute(name = "onRedeliveryRef", required = false)
067 private String onRedeliveryRef;
068 @XmlElementRef
069 private List<ProcessorDefinition> outputs = new ArrayList<ProcessorDefinition>();
070 @XmlTransient
071 private List<Class> exceptionClasses;
072 @XmlTransient
073 private Processor errorHandler;
074 @XmlTransient
075 private Predicate handledPolicy;
076 @XmlTransient
077 private Predicate retryUntilPolicy;
078 @XmlTransient
079 private Processor onRedelivery;
080
081 public OnExceptionDefinition() {
082 }
083
084 public OnExceptionDefinition(List<Class> exceptionClasses) {
085 this.exceptionClasses = exceptionClasses;
086 }
087
088 public OnExceptionDefinition(Class exceptionType) {
089 exceptionClasses = new ArrayList<Class>();
090 exceptionClasses.add(exceptionType);
091 }
092
093 @Override
094 public String getShortName() {
095 return "onException";
096 }
097
098 @Override
099 public String toString() {
100 return "OnException[" + getExceptionClasses() + (onWhen != null ? " " + onWhen : "") + " -> " + getOutputs() + "]";
101 }
102
103 /**
104 * Allows an exception handler to create a new redelivery policy for this exception type
105 * @param context the camel context
106 * @param parentPolicy the current redelivery policy
107 * @return a newly created redelivery policy, or return the original policy if no customization is required
108 * for this exception handler.
109 */
110 public RedeliveryPolicy createRedeliveryPolicy(CamelContext context, RedeliveryPolicy parentPolicy) {
111 if (redeliveryPolicy != null) {
112 return redeliveryPolicy.createRedeliveryPolicy(context, parentPolicy);
113 } else if (errorHandler != null) {
114 // lets create a new error handler that has no retries
115 RedeliveryPolicy answer = parentPolicy.copy();
116 answer.setMaximumRedeliveries(0);
117 return answer;
118 }
119 return parentPolicy;
120 }
121
122 public void addRoutes(RouteContext routeContext, Collection<Route> routes) throws Exception {
123 setHandledFromExpressionType(routeContext);
124 setRetryUntilFromExpressionType(routeContext);
125 // lets attach a processor to an error handler
126 errorHandler = routeContext.createProcessor(this);
127 ErrorHandlerBuilder builder = routeContext.getRoute().getErrorHandlerBuilder();
128 builder.addErrorHandlers(this);
129
130 // lookup onRedelivery if ref is provided
131 if (ObjectHelper.isNotEmpty(onRedeliveryRef)) {
132 onRedelivery = routeContext.lookup(onRedeliveryRef, Processor.class);
133 }
134 }
135
136 @Override
137 public CatchProcessor createProcessor(RouteContext routeContext) throws Exception {
138 Processor childProcessor = routeContext.createProcessor(this);
139 return new CatchProcessor(getExceptionClasses(), childProcessor);
140 }
141
142
143 // Fluent API
144 //-------------------------------------------------------------------------
145
146 @Override
147 public OnExceptionDefinition onException(Class exceptionType) {
148 getExceptionClasses().add(exceptionType);
149 return this;
150 }
151
152 /**
153 * Sets whether the exchange should be marked as handled or not.
154 *
155 * @param handled handled or not
156 * @return the builder
157 */
158 public OnExceptionDefinition handled(boolean handled) {
159 ConstantLanguage constant = new ConstantLanguage();
160 return handled(constant.createPredicate(Boolean.toString(handled)));
161 }
162
163 /**
164 * Sets whether the exchange should be marked as handled or not.
165 *
166 * @param handled predicate that determines true or false
167 * @return the builder
168 */
169 public OnExceptionDefinition handled(Predicate handled) {
170 setHandledPolicy(handled);
171 return this;
172 }
173
174 /**
175 * Sets whether the exchange should be marked as handled or not.
176 *
177 * @param handled expression that determines true or false
178 * @return the builder
179 */
180 public OnExceptionDefinition handled(Expression handled) {
181 setHandledPolicy(toPredicate(handled));
182 return this;
183 }
184
185 /**
186 * Sets an additional predicate that should be true before the onException is triggered.
187 * <p/>
188 * To be used for fine grained controlling whether a thrown exception should be intercepted
189 * by this exception type or not.
190 *
191 * @param predicate predicate that determines true or false
192 * @return the builder
193 */
194 public OnExceptionDefinition onWhen(Predicate predicate) {
195 setOnWhen(new WhenDefinition(predicate));
196 return this;
197 }
198
199 /**
200 * Creates an expression to configure an additional predicate that should be true before the
201 * onException is triggered.
202 * <p/>
203 * To be used for fine grained controlling whether a thrown exception should be intercepted
204 * by this exception type or not.
205 *
206 * @return the expression clause to configure
207 */
208 public ExpressionClause<OnExceptionDefinition> onWhen() {
209 onWhen = new WhenDefinition();
210 ExpressionClause<OnExceptionDefinition> clause = new ExpressionClause<OnExceptionDefinition>(this);
211 onWhen.setExpression(clause);
212 return clause;
213 }
214
215 /**
216 * Sets the retry until predicate.
217 *
218 * @param until predicate that determines when to stop retrying
219 * @return the builder
220 */
221 public OnExceptionDefinition retryUntil(Predicate until) {
222 setRetryUntilPolicy(until);
223 return this;
224 }
225
226 /**
227 * Sets the retry until expression.
228 *
229 * @param until expression that determines when to stop retrying
230 * @return the builder
231 */
232 public OnExceptionDefinition retryUntil(Expression until) {
233 setRetryUntilPolicy(toPredicate(until));
234 return this;
235 }
236
237 /**
238 * Sets the back off multiplier
239 *
240 * @param backOffMultiplier the back off multiplier
241 * @return the builder
242 */
243 public OnExceptionDefinition backOffMultiplier(double backOffMultiplier) {
244 getOrCreateRedeliveryPolicy().backOffMultiplier(backOffMultiplier);
245 return this;
246 }
247
248 /**
249 * Sets the collision avoidance factor
250 *
251 * @param collisionAvoidanceFactor the factor
252 * @return the builder
253 */
254 public OnExceptionDefinition collisionAvoidanceFactor(double collisionAvoidanceFactor) {
255 getOrCreateRedeliveryPolicy().collisionAvoidanceFactor(collisionAvoidanceFactor);
256 return this;
257 }
258
259 /**
260 * Sets the collision avoidance percentage
261 *
262 * @param collisionAvoidancePercent the percentage
263 * @return the builder
264 */
265 public OnExceptionDefinition collisionAvoidancePercent(short collisionAvoidancePercent) {
266 getOrCreateRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent);
267 return this;
268 }
269
270 /**
271 * Sets the fixed delay between redeliveries
272 *
273 * @param delay delay in millis
274 * @return the builder
275 */
276 public OnExceptionDefinition redeliveryDelay(long delay) {
277 getOrCreateRedeliveryPolicy().redeliveryDelay(delay);
278 return this;
279 }
280
281 /**
282 * Sets the logging level to use when retries has exhausted
283 *
284 * @param retriesExhaustedLogLevel the logging level
285 * @return the builder
286 */
287 public OnExceptionDefinition retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) {
288 getOrCreateRedeliveryPolicy().retriesExhaustedLogLevel(retriesExhaustedLogLevel);
289 return this;
290 }
291
292 /**
293 * Sets the logging level to use for logging retry attempts
294 *
295 * @param retryAttemptedLogLevel the logging level
296 * @return the builder
297 */
298 public OnExceptionDefinition retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) {
299 getOrCreateRedeliveryPolicy().retryAttemptedLogLevel(retryAttemptedLogLevel);
300 return this;
301 }
302
303 /**
304 * Sets the maximum redeliveries
305 * <ul>
306 * <li>5 = default value</li>
307 * <li>0 = no redeliveries</li>
308 * <li>-1 = redeliver forever</li>
309 * </ul>
310 *
311 * @param maximumRedeliveries the value
312 * @return the builder
313 */
314 public OnExceptionDefinition maximumRedeliveries(int maximumRedeliveries) {
315 getOrCreateRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries);
316 return this;
317 }
318
319 /**
320 * Turn on collision avoidance.
321 *
322 * @return the builder
323 */
324 public OnExceptionDefinition useCollisionAvoidance() {
325 getOrCreateRedeliveryPolicy().useCollisionAvoidance();
326 return this;
327 }
328
329 /**
330 * Turn on exponential backk off
331 *
332 * @return the builder
333 */
334 public OnExceptionDefinition useExponentialBackOff() {
335 getOrCreateRedeliveryPolicy().useExponentialBackOff();
336 return this;
337 }
338
339 /**
340 * Sets the maximum delay between redelivery
341 *
342 * @param maximumRedeliveryDelay the delay in millis
343 * @return the builder
344 */
345 public OnExceptionDefinition maximumRedeliveryDelay(long maximumRedeliveryDelay) {
346 getOrCreateRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay);
347 return this;
348 }
349
350 /**
351 * Sets a processor that should be processed <b>before</b> a redelivey attempt.
352 * <p/>
353 * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered.
354 */
355 public OnExceptionDefinition onRedelivery(Processor processor) {
356 setOnRedelivery(processor);
357 return this;
358 }
359
360 // Properties
361 //-------------------------------------------------------------------------
362 public List<ProcessorDefinition> getOutputs() {
363 return outputs;
364 }
365
366 public void setOutputs(List<ProcessorDefinition> outputs) {
367 this.outputs = outputs;
368 }
369
370 public List<Class> getExceptionClasses() {
371 if (exceptionClasses == null) {
372 exceptionClasses = createExceptionClasses();
373 }
374 return exceptionClasses;
375 }
376
377 public void setExceptionClasses(List<Class> exceptionClasses) {
378 this.exceptionClasses = exceptionClasses;
379 }
380
381 public List<String> getExceptions() {
382 return exceptions;
383 }
384
385 public void setExceptions(List<String> exceptions) {
386 this.exceptions = exceptions;
387 }
388
389 public Processor getErrorHandler() {
390 return errorHandler;
391 }
392
393 public RedeliveryPolicyDefinition getRedeliveryPolicy() {
394 return redeliveryPolicy;
395 }
396
397 public void setRedeliveryPolicy(RedeliveryPolicyDefinition redeliveryPolicy) {
398 this.redeliveryPolicy = redeliveryPolicy;
399 }
400
401 public Predicate getHandledPolicy() {
402 return handledPolicy;
403 }
404
405 public void setHandled(ExpressionSubElementDefinition handled) {
406 this.handled = handled;
407 }
408
409 public ExpressionSubElementDefinition getHandled() {
410 return handled;
411 }
412
413 public void setHandledPolicy(Predicate handledPolicy) {
414 this.handledPolicy = handledPolicy;
415 }
416
417 public WhenDefinition getOnWhen() {
418 return onWhen;
419 }
420
421 public void setOnWhen(WhenDefinition onWhen) {
422 this.onWhen = onWhen;
423 }
424
425 public ExpressionSubElementDefinition getRetryUntil() {
426 return retryUntil;
427 }
428
429 public void setRetryUntil(ExpressionSubElementDefinition retryUntil) {
430 this.retryUntil = retryUntil;
431 }
432
433 public Predicate getRetryUntilPolicy() {
434 return retryUntilPolicy;
435 }
436
437 public void setRetryUntilPolicy(Predicate retryUntilPolicy) {
438 this.retryUntilPolicy = retryUntilPolicy;
439 }
440
441 public Processor getOnRedelivery() {
442 return onRedelivery;
443 }
444
445 public void setOnRedelivery(Processor onRedelivery) {
446 this.onRedelivery = onRedelivery;
447 }
448
449 public String getOnRedeliveryRef() {
450 return onRedeliveryRef;
451 }
452
453 public void setOnRedeliveryRef(String onRedeliveryRef) {
454 this.onRedeliveryRef = onRedeliveryRef;
455 }
456
457
458 // Implementation methods
459 //-------------------------------------------------------------------------
460 protected RedeliveryPolicyDefinition getOrCreateRedeliveryPolicy() {
461 if (redeliveryPolicy == null) {
462 redeliveryPolicy = new RedeliveryPolicyDefinition();
463 }
464 return redeliveryPolicy;
465 }
466
467 protected List<Class> createExceptionClasses() {
468 List<String> list = getExceptions();
469 List<Class> answer = new ArrayList<Class>(list.size());
470 for (String name : list) {
471 Class type = ObjectHelper.loadClass(name, getClass().getClassLoader());
472 answer.add(type);
473 }
474 return answer;
475 }
476
477
478 private void setHandledFromExpressionType(RouteContext routeContext) {
479 if (getHandled() != null && handledPolicy == null && routeContext != null) {
480 handled(getHandled().createPredicate(routeContext));
481 }
482 }
483
484 private void setRetryUntilFromExpressionType(RouteContext routeContext) {
485 if (getRetryUntil() != null && retryUntilPolicy == null && routeContext != null) {
486 retryUntil(getRetryUntil().createPredicate(routeContext));
487 }
488 }
489
490 }