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 */ 017package org.apache.camel.reifier.errorhandler; 018 019import java.util.HashMap; 020import java.util.Map; 021import java.util.function.Function; 022 023import org.apache.camel.CamelContext; 024import org.apache.camel.ErrorHandlerFactory; 025import org.apache.camel.ExtendedCamelContext; 026import org.apache.camel.NamedNode; 027import org.apache.camel.Processor; 028import org.apache.camel.RuntimeCamelException; 029import org.apache.camel.builder.DeadLetterChannelBuilder; 030import org.apache.camel.builder.DefaultErrorHandlerBuilder; 031import org.apache.camel.builder.ErrorHandlerBuilder; 032import org.apache.camel.builder.ErrorHandlerBuilderRef; 033import org.apache.camel.builder.ErrorHandlerBuilderSupport; 034import org.apache.camel.builder.NoErrorHandlerBuilder; 035import org.apache.camel.model.OnExceptionDefinition; 036import org.apache.camel.model.RedeliveryPolicyDefinition; 037import org.apache.camel.model.RouteDefinition; 038import org.apache.camel.processor.ErrorHandler; 039import org.apache.camel.processor.errorhandler.ErrorHandlerSupport; 040import org.apache.camel.processor.errorhandler.ExceptionPolicy; 041import org.apache.camel.processor.errorhandler.ExceptionPolicy.RedeliveryOption; 042import org.apache.camel.processor.errorhandler.RedeliveryErrorHandler; 043import org.apache.camel.processor.errorhandler.RedeliveryPolicy; 044import org.apache.camel.spi.RouteContext; 045import org.apache.camel.support.CamelContextHelper; 046import org.apache.camel.util.ObjectHelper; 047 048public abstract class ErrorHandlerReifier<T extends ErrorHandlerBuilderSupport> { 049 050 public static final String DEFAULT_ERROR_HANDLER_BUILDER = "CamelDefaultErrorHandlerBuilder"; 051 private static final Map<Class<?>, Function<ErrorHandlerFactory, ErrorHandlerReifier<? extends ErrorHandlerFactory>>> ERROR_HANDLERS; 052 static { 053 Map<Class<?>, Function<ErrorHandlerFactory, ErrorHandlerReifier<? extends ErrorHandlerFactory>>> map = new HashMap<>(); 054 map.put(DeadLetterChannelBuilder.class, DeadLetterChannelReifier::new); 055 map.put(DefaultErrorHandlerBuilder.class, DefaultErrorHandlerReifier::new); 056 map.put(ErrorHandlerBuilderRef.class, ErrorHandlerRefReifier::new); 057 map.put(NoErrorHandlerBuilder.class, NoErrorHandlerReifier::new); 058 ERROR_HANDLERS = map; 059 } 060 061 protected T definition; 062 063 /** 064 * Utility classes should not have a public constructor. 065 */ 066 ErrorHandlerReifier(T definition) { 067 this.definition = definition; 068 } 069 070 public static void registerReifier(Class<?> errorHandlerClass, Function<ErrorHandlerFactory, ErrorHandlerReifier<? extends ErrorHandlerFactory>> creator) { 071 ERROR_HANDLERS.put(errorHandlerClass, creator); 072 } 073 074 public static ErrorHandlerReifier<? extends ErrorHandlerFactory> reifier(ErrorHandlerFactory definition) { 075 Function<ErrorHandlerFactory, ErrorHandlerReifier<? extends ErrorHandlerFactory>> reifier = ERROR_HANDLERS.get(definition.getClass()); 076 if (reifier != null) { 077 return reifier.apply(definition); 078 } else if (definition instanceof ErrorHandlerBuilderSupport) { 079 return new ErrorHandlerReifier<ErrorHandlerBuilderSupport>((ErrorHandlerBuilderSupport)definition) { 080 @Override 081 public Processor createErrorHandler(RouteContext routeContext, Processor processor) throws Exception { 082 return definition.createErrorHandler(routeContext, processor); 083 } 084 }; 085 } else { 086 throw new IllegalStateException("Unsupported definition: " + definition); 087 } 088 } 089 090 public static ExceptionPolicy createExceptionPolicy(OnExceptionDefinition def, RouteContext routeContext) { 091 return new ExceptionPolicy(def.getId(), CamelContextHelper.getRouteId(def), def.getUseOriginalMessagePolicy() != null && def.getUseOriginalMessagePolicy(), 092 def.getUseOriginalBodyPolicy() != null && def.getUseOriginalBodyPolicy(), ObjectHelper.isNotEmpty(def.getOutputs()), def.getHandledPolicy(), 093 def.getContinuedPolicy(), def.getRetryWhilePolicy(), def.getOnRedelivery(), def.getOnExceptionOccurred(), def.getRedeliveryPolicyRef(), 094 getRedeliveryPolicy(def.getRedeliveryPolicyType()), def.getExceptions()); 095 } 096 097 private static Map<RedeliveryOption, String> getRedeliveryPolicy(RedeliveryPolicyDefinition definition) { 098 if (definition == null) { 099 return null; 100 } 101 Map<RedeliveryOption, String> policy = new HashMap<>(); 102 setOption(policy, RedeliveryOption.maximumRedeliveries, definition.getMaximumRedeliveries()); 103 setOption(policy, RedeliveryOption.redeliveryDelay, definition.getRedeliveryDelay()); 104 setOption(policy, RedeliveryOption.asyncDelayedRedelivery, definition.getAsyncDelayedRedelivery()); 105 setOption(policy, RedeliveryOption.backOffMultiplier, definition.getBackOffMultiplier()); 106 setOption(policy, RedeliveryOption.useExponentialBackOff, definition.getUseExponentialBackOff()); 107 setOption(policy, RedeliveryOption.collisionAvoidanceFactor, definition.getCollisionAvoidanceFactor()); 108 setOption(policy, RedeliveryOption.useCollisionAvoidance, definition.getUseCollisionAvoidance()); 109 setOption(policy, RedeliveryOption.maximumRedeliveryDelay, definition.getMaximumRedeliveryDelay()); 110 setOption(policy, RedeliveryOption.retriesExhaustedLogLevel, definition.getRetriesExhaustedLogLevel()); 111 setOption(policy, RedeliveryOption.retryAttemptedLogLevel, definition.getRetryAttemptedLogLevel()); 112 setOption(policy, RedeliveryOption.retryAttemptedLogInterval, definition.getRetryAttemptedLogInterval()); 113 setOption(policy, RedeliveryOption.logRetryAttempted, definition.getLogRetryAttempted()); 114 setOption(policy, RedeliveryOption.logStackTrace, definition.getLogStackTrace()); 115 setOption(policy, RedeliveryOption.logRetryStackTrace, definition.getLogRetryStackTrace()); 116 setOption(policy, RedeliveryOption.logHandled, definition.getLogHandled()); 117 setOption(policy, RedeliveryOption.logNewException, definition.getLogNewException()); 118 setOption(policy, RedeliveryOption.logContinued, definition.getLogContinued()); 119 setOption(policy, RedeliveryOption.logExhausted, definition.getLogExhausted()); 120 setOption(policy, RedeliveryOption.logExhaustedMessageHistory, definition.getLogExhaustedMessageHistory()); 121 setOption(policy, RedeliveryOption.logExhaustedMessageBody, definition.getLogExhaustedMessageBody()); 122 setOption(policy, RedeliveryOption.disableRedelivery, definition.getDisableRedelivery()); 123 setOption(policy, RedeliveryOption.delayPattern, definition.getDelayPattern()); 124 setOption(policy, RedeliveryOption.allowRedeliveryWhileStopping, definition.getAllowRedeliveryWhileStopping()); 125 setOption(policy, RedeliveryOption.exchangeFormatterRef, definition.getExchangeFormatterRef()); 126 return policy; 127 } 128 129 private static void setOption(Map<RedeliveryOption, String> policy, RedeliveryOption option, Object value) { 130 if (value != null) { 131 policy.put(option, value.toString()); 132 } 133 } 134 135 /** 136 * Lookup the error handler by the given ref 137 * 138 * @param routeContext the route context 139 * @param ref reference id for the error handler 140 * @return the error handler 141 */ 142 public static ErrorHandlerFactory lookupErrorHandlerFactory(RouteContext routeContext, String ref) { 143 return lookupErrorHandlerFactory(routeContext, ref, true); 144 } 145 146 /** 147 * Lookup the error handler by the given ref 148 * 149 * @param routeContext the route context 150 * @param ref reference id for the error handler 151 * @param mandatory whether the error handler must exists, if not a 152 * {@link org.apache.camel.NoSuchBeanException} is thrown 153 * @return the error handler 154 */ 155 public static ErrorHandlerFactory lookupErrorHandlerFactory(RouteContext routeContext, String ref, boolean mandatory) { 156 ErrorHandlerFactory answer; 157 158 // if the ref is the default then we do not have any explicit error 159 // handler configured 160 // if that is the case then use error handlers configured on the route, 161 // as for instance 162 // the transacted error handler could have been configured on the route 163 // so we should use that one 164 if (!isErrorHandlerFactoryConfigured(ref)) { 165 // see if there has been configured a error handler builder on the route 166 // TODO: Avoid using RouteDefinition - tests should pass: https://issues.apache.org/jira/browse/CAMEL-13984 167 RouteDefinition route = (RouteDefinition)routeContext.getRoute(); 168 answer = route.getErrorHandlerFactory(); 169 // check if its also a ref with no error handler configuration like me 170 if (answer instanceof ErrorHandlerBuilderRef) { 171 ErrorHandlerBuilderRef other = (ErrorHandlerBuilderRef)answer; 172 String otherRef = other.getRef(); 173 if (!isErrorHandlerFactoryConfigured(otherRef)) { 174 // the other has also no explicit error handler configured 175 // then fallback to the handler 176 // configured on the parent camel context 177 answer = lookupErrorHandlerFactory(routeContext.getCamelContext()); 178 } 179 if (answer == null) { 180 // the other has also no explicit error handler configured 181 // then fallback to the default error handler 182 // otherwise we could recursive loop forever (triggered by 183 // createErrorHandler method) 184 answer = new DefaultErrorHandlerBuilder(); 185 } 186 // inherit the error handlers from the other as they are to be 187 // shared 188 // this is needed by camel-spring when none error handler has 189 // been explicit configured 190 routeContext.addErrorHandlerFactoryReference(other, answer); 191 } 192 } else { 193 // use specific configured error handler 194 if (mandatory) { 195 answer = routeContext.mandatoryLookup(ref, ErrorHandlerBuilder.class); 196 } else { 197 answer = routeContext.lookup(ref, ErrorHandlerBuilder.class); 198 } 199 } 200 201 return answer; 202 } 203 204 protected static ErrorHandlerFactory lookupErrorHandlerFactory(CamelContext camelContext) { 205 ErrorHandlerFactory answer = camelContext.adapt(ExtendedCamelContext.class).getErrorHandlerFactory(); 206 if (answer instanceof ErrorHandlerBuilderRef) { 207 ErrorHandlerBuilderRef other = (ErrorHandlerBuilderRef)answer; 208 String otherRef = other.getRef(); 209 if (isErrorHandlerFactoryConfigured(otherRef)) { 210 answer = camelContext.getRegistry().lookupByNameAndType(otherRef, ErrorHandlerBuilder.class); 211 if (answer == null) { 212 throw new IllegalArgumentException("ErrorHandlerBuilder with id " + otherRef + " not found in registry."); 213 } 214 } 215 } 216 217 return answer; 218 } 219 220 /** 221 * Returns whether a specific error handler builder has been configured or 222 * not. 223 * <p/> 224 * Can be used to test if none has been configured and then install a custom 225 * error handler builder replacing the default error handler (that would 226 * have been used as fallback otherwise). <br/> 227 * This is for instance used by the transacted policy to setup a 228 * TransactedErrorHandlerBuilder in camel-spring. 229 */ 230 public static boolean isErrorHandlerFactoryConfigured(String ref) { 231 return !DEFAULT_ERROR_HANDLER_BUILDER.equals(ref); 232 } 233 234 /** 235 * Creates the error handler 236 * 237 * @param routeContext the route context 238 * @param processor the outer processor 239 * @return the error handler 240 * @throws Exception is thrown if the error handler could not be created 241 */ 242 public abstract Processor createErrorHandler(RouteContext routeContext, Processor processor) throws Exception; 243 244 public void configure(RouteContext routeContext, ErrorHandler handler) { 245 if (handler instanceof ErrorHandlerSupport) { 246 ErrorHandlerSupport handlerSupport = (ErrorHandlerSupport)handler; 247 248 for (NamedNode exception : routeContext.getErrorHandlers(definition)) { 249 ErrorHandlerBuilderSupport.addExceptionPolicy(handlerSupport, routeContext, (OnExceptionDefinition)exception); 250 } 251 } 252 if (handler instanceof RedeliveryErrorHandler) { 253 boolean original = ((RedeliveryErrorHandler)handler).isUseOriginalMessagePolicy() || ((RedeliveryErrorHandler)handler).isUseOriginalMessagePolicy(); 254 if (original) { 255 // ensure allow original is turned on 256 routeContext.setAllowUseOriginalMessage(true); 257 } 258 } 259 } 260 261 /** 262 * Note: Not for end users - this method is used internally by 263 * camel-blueprint 264 */ 265 public static RedeliveryPolicy createRedeliveryPolicy(RedeliveryPolicyDefinition definition, CamelContext context, RedeliveryPolicy parentPolicy) { 266 RedeliveryPolicy answer; 267 if (parentPolicy != null) { 268 answer = parentPolicy.copy(); 269 } else { 270 answer = new RedeliveryPolicy(); 271 } 272 273 try { 274 275 // copy across the properties - if they are set 276 if (definition.getMaximumRedeliveries() != null) { 277 answer.setMaximumRedeliveries(CamelContextHelper.parseInteger(context, definition.getMaximumRedeliveries())); 278 } 279 if (definition.getRedeliveryDelay() != null) { 280 answer.setRedeliveryDelay(CamelContextHelper.parseLong(context, definition.getRedeliveryDelay())); 281 } 282 if (definition.getAsyncDelayedRedelivery() != null) { 283 answer.setAsyncDelayedRedelivery(CamelContextHelper.parseBoolean(context, definition.getAsyncDelayedRedelivery())); 284 } 285 if (definition.getRetriesExhaustedLogLevel() != null) { 286 answer.setRetriesExhaustedLogLevel(definition.getRetriesExhaustedLogLevel()); 287 } 288 if (definition.getRetryAttemptedLogLevel() != null) { 289 answer.setRetryAttemptedLogLevel(definition.getRetryAttemptedLogLevel()); 290 } 291 if (definition.getRetryAttemptedLogInterval() != null) { 292 answer.setRetryAttemptedLogInterval(CamelContextHelper.parseInteger(context, definition.getRetryAttemptedLogInterval())); 293 } 294 if (definition.getBackOffMultiplier() != null) { 295 answer.setBackOffMultiplier(CamelContextHelper.parseDouble(context, definition.getBackOffMultiplier())); 296 } 297 if (definition.getUseExponentialBackOff() != null) { 298 answer.setUseExponentialBackOff(CamelContextHelper.parseBoolean(context, definition.getUseExponentialBackOff())); 299 } 300 if (definition.getCollisionAvoidanceFactor() != null) { 301 answer.setCollisionAvoidanceFactor(CamelContextHelper.parseDouble(context, definition.getCollisionAvoidanceFactor())); 302 } 303 if (definition.getUseCollisionAvoidance() != null) { 304 answer.setUseCollisionAvoidance(CamelContextHelper.parseBoolean(context, definition.getUseCollisionAvoidance())); 305 } 306 if (definition.getMaximumRedeliveryDelay() != null) { 307 answer.setMaximumRedeliveryDelay(CamelContextHelper.parseLong(context, definition.getMaximumRedeliveryDelay())); 308 } 309 if (definition.getLogStackTrace() != null) { 310 answer.setLogStackTrace(CamelContextHelper.parseBoolean(context, definition.getLogStackTrace())); 311 } 312 if (definition.getLogRetryStackTrace() != null) { 313 answer.setLogRetryStackTrace(CamelContextHelper.parseBoolean(context, definition.getLogRetryStackTrace())); 314 } 315 if (definition.getLogHandled() != null) { 316 answer.setLogHandled(CamelContextHelper.parseBoolean(context, definition.getLogHandled())); 317 } 318 if (definition.getLogNewException() != null) { 319 answer.setLogNewException(CamelContextHelper.parseBoolean(context, definition.getLogNewException())); 320 } 321 if (definition.getLogContinued() != null) { 322 answer.setLogContinued(CamelContextHelper.parseBoolean(context, definition.getLogContinued())); 323 } 324 if (definition.getLogRetryAttempted() != null) { 325 answer.setLogRetryAttempted(CamelContextHelper.parseBoolean(context, definition.getLogRetryAttempted())); 326 } 327 if (definition.getLogExhausted() != null) { 328 answer.setLogExhausted(CamelContextHelper.parseBoolean(context, definition.getLogExhausted())); 329 } 330 if (definition.getLogExhaustedMessageHistory() != null) { 331 answer.setLogExhaustedMessageHistory(CamelContextHelper.parseBoolean(context, definition.getLogExhaustedMessageHistory())); 332 } 333 if (definition.getLogExhaustedMessageBody() != null) { 334 answer.setLogExhaustedMessageBody(CamelContextHelper.parseBoolean(context, definition.getLogExhaustedMessageBody())); 335 } 336 if (definition.getDisableRedelivery() != null) { 337 if (CamelContextHelper.parseBoolean(context, definition.getDisableRedelivery())) { 338 answer.setMaximumRedeliveries(0); 339 } 340 } 341 if (definition.getDelayPattern() != null) { 342 answer.setDelayPattern(CamelContextHelper.parseText(context, definition.getDelayPattern())); 343 } 344 if (definition.getAllowRedeliveryWhileStopping() != null) { 345 answer.setAllowRedeliveryWhileStopping(CamelContextHelper.parseBoolean(context, definition.getAllowRedeliveryWhileStopping())); 346 } 347 if (definition.getExchangeFormatterRef() != null) { 348 answer.setExchangeFormatterRef(CamelContextHelper.parseText(context, definition.getExchangeFormatterRef())); 349 } 350 } catch (Exception e) { 351 throw RuntimeCamelException.wrapRuntimeCamelException(e); 352 } 353 354 return answer; 355 } 356 357}