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; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import org.apache.camel.Predicate; 023import org.apache.camel.Processor; 024import org.apache.camel.builder.ErrorHandlerBuilder; 025import org.apache.camel.model.OnExceptionDefinition; 026import org.apache.camel.model.ProcessorDefinition; 027import org.apache.camel.processor.CatchProcessor; 028import org.apache.camel.processor.FatalFallbackErrorHandler; 029import org.apache.camel.spi.ClassResolver; 030import org.apache.camel.spi.RouteContext; 031import org.apache.camel.support.CamelContextHelper; 032import org.apache.camel.util.ObjectHelper; 033 034public class OnExceptionReifier extends ProcessorReifier<OnExceptionDefinition> { 035 036 public OnExceptionReifier(ProcessorDefinition<?> definition) { 037 super((OnExceptionDefinition)definition); 038 } 039 040 @Override 041 public void addRoutes(RouteContext routeContext) throws Exception { 042 // assign whether this was a route scoped onException or not 043 // we need to know this later when setting the parent, as only route 044 // scoped should have parent 045 // Note: this logic can possible be removed when the Camel routing 046 // engine decides at runtime 047 // to apply onException in a more dynamic fashion than current code base 048 // and therefore is in a better position to decide among context/route 049 // scoped OnException at runtime 050 if (definition.getRouteScoped() == null) { 051 definition.setRouteScoped(definition.getParent() != null); 052 } 053 054 setHandledFromExpressionType(routeContext); 055 setContinuedFromExpressionType(routeContext); 056 setRetryWhileFromExpressionType(routeContext); 057 setOnRedeliveryFromRedeliveryRef(routeContext); 058 setOnExceptionOccurredFromOnExceptionOccurredRef(routeContext); 059 060 // must validate configuration before creating processor 061 definition.validateConfiguration(); 062 063 if (definition.getUseOriginalMessagePolicy() != null && definition.getUseOriginalMessagePolicy()) { 064 // ensure allow original is turned on 065 routeContext.setAllowUseOriginalMessage(true); 066 } 067 068 // lets attach this on exception to the route error handler 069 Processor child = createOutputsProcessor(routeContext); 070 if (child != null) { 071 // wrap in our special safe fallback error handler if OnException 072 // have child output 073 Processor errorHandler = new FatalFallbackErrorHandler(child); 074 String id = getId(definition, routeContext); 075 routeContext.setOnException(id, errorHandler); 076 } 077 // lookup the error handler builder 078 ErrorHandlerBuilder builder = (ErrorHandlerBuilder)routeContext.getErrorHandlerFactory(); 079 // and add this as error handlers 080 routeContext.addErrorHandler(builder, definition); 081 } 082 083 @Override 084 public CatchProcessor createProcessor(RouteContext routeContext) throws Exception { 085 // load exception classes 086 List<Class<? extends Throwable>> classes = null; 087 if (definition.getExceptions() != null && !definition.getExceptions().isEmpty()) { 088 classes = createExceptionClasses(routeContext.getCamelContext().getClassResolver()); 089 } 090 091 if (definition.getUseOriginalMessagePolicy() != null && definition.getUseOriginalMessagePolicy()) { 092 // ensure allow original is turned on 093 routeContext.setAllowUseOriginalMessage(true); 094 } 095 096 // must validate configuration before creating processor 097 definition.validateConfiguration(); 098 099 Processor childProcessor = this.createChildProcessor(routeContext, false); 100 101 Predicate when = null; 102 if (definition.getOnWhen() != null) { 103 when = definition.getOnWhen().getExpression().createPredicate(routeContext); 104 } 105 106 Predicate handle = null; 107 if (definition.getHandled() != null) { 108 handle = definition.getHandled().createPredicate(routeContext); 109 } 110 111 return new CatchProcessor(classes, childProcessor, when, handle); 112 } 113 114 protected List<Class<? extends Throwable>> createExceptionClasses(ClassResolver resolver) throws ClassNotFoundException { 115 List<String> list = definition.getExceptions(); 116 List<Class<? extends Throwable>> answer = new ArrayList<>(list.size()); 117 for (String name : list) { 118 Class<? extends Throwable> type = resolver.resolveMandatoryClass(name, Throwable.class); 119 answer.add(type); 120 } 121 return answer; 122 } 123 124 private void setHandledFromExpressionType(RouteContext routeContext) { 125 if (definition.getHandled() != null && definition.getHandledPolicy() == null && routeContext != null) { 126 definition.handled(definition.getHandled().createPredicate(routeContext)); 127 } 128 } 129 130 private void setContinuedFromExpressionType(RouteContext routeContext) { 131 if (definition.getContinued() != null && definition.getContinuedPolicy() == null && routeContext != null) { 132 definition.continued(definition.getContinued().createPredicate(routeContext)); 133 } 134 } 135 136 private void setRetryWhileFromExpressionType(RouteContext routeContext) { 137 if (definition.getRetryWhile() != null && definition.getRetryWhilePolicy() == null && routeContext != null) { 138 definition.retryWhile(definition.getRetryWhile().createPredicate(routeContext)); 139 } 140 } 141 142 private void setOnRedeliveryFromRedeliveryRef(RouteContext routeContext) { 143 // lookup onRedelivery if ref is provided 144 if (ObjectHelper.isNotEmpty(definition.getOnRedeliveryRef())) { 145 // if ref is provided then use mandatory lookup to fail if not found 146 Processor onRedelivery = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), definition.getOnRedeliveryRef(), Processor.class); 147 definition.setOnRedelivery(onRedelivery); 148 } 149 } 150 151 private void setOnExceptionOccurredFromOnExceptionOccurredRef(RouteContext routeContext) { 152 // lookup onRedelivery if ref is provided 153 if (ObjectHelper.isNotEmpty(definition.getOnExceptionOccurredRef())) { 154 // if ref is provided then use mandatory lookup to fail if not found 155 Processor onExceptionOccurred = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), definition.getOnExceptionOccurredRef(), Processor.class); 156 definition.setOnExceptionOccurred(onExceptionOccurred); 157 } 158 } 159 160}