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 }