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.builder; 018 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.camel.ErrorHandlerFactory; 024import org.apache.camel.Processor; 025import org.apache.camel.model.ModelCamelContext; 026import org.apache.camel.model.OnExceptionDefinition; 027import org.apache.camel.spi.RouteContext; 028import org.apache.camel.util.ObjectHelper; 029 030/** 031 * Represents a proxy to an error handler builder which is resolved by named reference 032 * 033 * @version 034 */ 035public class ErrorHandlerBuilderRef extends ErrorHandlerBuilderSupport { 036 public static final String DEFAULT_ERROR_HANDLER_BUILDER = "CamelDefaultErrorHandlerBuilder"; 037 private final String ref; 038 private final Map<RouteContext, ErrorHandlerBuilder> handlers = new HashMap<>(); 039 private boolean supportTransacted; 040 041 public ErrorHandlerBuilderRef(String ref) { 042 this.ref = ref; 043 } 044 045 @Override 046 public void addErrorHandlers(RouteContext routeContext, OnExceptionDefinition exception) { 047 ErrorHandlerBuilder handler = handlers.get(routeContext); 048 if (handler != null) { 049 handler.addErrorHandlers(routeContext, exception); 050 } 051 super.addErrorHandlers(routeContext, exception); 052 } 053 054 @Override 055 public boolean removeOnExceptionList(String id) { 056 for (RouteContext routeContext : handlers.keySet()) { 057 if (getRouteId(routeContext).equals(id)) { 058 handlers.remove(routeContext); 059 break; 060 } 061 } 062 return super.removeOnExceptionList(id); 063 } 064 065 066 public Processor createErrorHandler(RouteContext routeContext, Processor processor) throws Exception { 067 ErrorHandlerBuilder handler = handlers.get(routeContext); 068 if (handler == null) { 069 handler = createErrorHandler(routeContext); 070 handlers.put(routeContext, handler); 071 } 072 return handler.createErrorHandler(routeContext, processor); 073 } 074 075 public boolean supportTransacted() { 076 return supportTransacted; 077 } 078 079 @Override 080 public ErrorHandlerBuilder cloneBuilder() { 081 ErrorHandlerBuilderRef answer = new ErrorHandlerBuilderRef(ref); 082 cloneBuilder(answer); 083 return answer; 084 } 085 086 protected void cloneBuilder(ErrorHandlerBuilderRef other) { 087 super.cloneBuilder(other); 088 089 // no need to copy the handlers 090 091 other.supportTransacted = supportTransacted; 092 } 093 094 /** 095 * Lookup the error handler by the given ref 096 * 097 * @param routeContext the route context 098 * @param ref reference id for the error handler 099 * @return the error handler 100 */ 101 public static ErrorHandlerFactory lookupErrorHandlerBuilder(RouteContext routeContext, String ref) { 102 return lookupErrorHandlerBuilder(routeContext, ref, true); 103 } 104 105 /** 106 * Lookup the error handler by the given ref 107 * 108 * @param routeContext the route context 109 * @param ref reference id for the error handler 110 * @param mandatory whether the error handler must exists, if not a {@link org.apache.camel.NoSuchBeanException} is thrown 111 * @return the error handler 112 */ 113 public static ErrorHandlerFactory lookupErrorHandlerBuilder(RouteContext routeContext, String ref, boolean mandatory) { 114 ErrorHandlerFactory answer; 115 116 // if the ref is the default then we do not have any explicit error handler configured 117 // if that is the case then use error handlers configured on the route, as for instance 118 // the transacted error handler could have been configured on the route so we should use that one 119 if (!isErrorHandlerBuilderConfigured(ref)) { 120 // see if there has been configured a route builder on the route 121 answer = routeContext.getRoute().getErrorHandlerBuilder(); 122 if (answer == null && routeContext.getRoute().getErrorHandlerRef() != null) { 123 answer = routeContext.lookup(routeContext.getRoute().getErrorHandlerRef(), ErrorHandlerBuilder.class); 124 } 125 if (answer == null) { 126 // fallback to the default error handler if none configured on the route 127 answer = new DefaultErrorHandlerBuilder(); 128 } 129 // check if its also a ref with no error handler configuration like me 130 if (answer instanceof ErrorHandlerBuilderRef) { 131 ErrorHandlerBuilderRef other = (ErrorHandlerBuilderRef) answer; 132 String otherRef = other.getRef(); 133 if (!isErrorHandlerBuilderConfigured(otherRef)) { 134 // the other has also no explicit error handler configured then fallback to the handler 135 // configured on the parent camel context 136 answer = lookupErrorHandlerBuilder((ModelCamelContext)routeContext.getCamelContext()); 137 } 138 if (answer == null) { 139 // the other has also no explicit error handler configured then fallback to the default error handler 140 // otherwise we could recursive loop forever (triggered by createErrorHandler method) 141 answer = new DefaultErrorHandlerBuilder(); 142 } 143 // inherit the error handlers from the other as they are to be shared 144 // this is needed by camel-spring when none error handler has been explicit configured 145 ((ErrorHandlerBuilder)answer).setErrorHandlers(routeContext, other.getErrorHandlers(routeContext)); 146 } 147 } else { 148 // use specific configured error handler 149 if (mandatory) { 150 answer = routeContext.mandatoryLookup(ref, ErrorHandlerBuilder.class); 151 } else { 152 answer = routeContext.lookup(ref, ErrorHandlerBuilder.class); 153 } 154 } 155 156 return answer; 157 } 158 159 protected static ErrorHandlerFactory lookupErrorHandlerBuilder(ModelCamelContext camelContext) { 160 @SuppressWarnings("deprecation") 161 ErrorHandlerFactory answer = camelContext.getErrorHandlerBuilder(); 162 if (answer instanceof ErrorHandlerBuilderRef) { 163 ErrorHandlerBuilderRef other = (ErrorHandlerBuilderRef) answer; 164 String otherRef = other.getRef(); 165 if (isErrorHandlerBuilderConfigured(otherRef)) { 166 answer = camelContext.getRegistry().lookupByNameAndType(otherRef, ErrorHandlerBuilder.class); 167 if (answer == null) { 168 throw new IllegalArgumentException("ErrorHandlerBuilder with id " + otherRef + " not found in registry."); 169 } 170 } 171 } 172 173 return answer; 174 } 175 176 /** 177 * Returns whether a specific error handler builder has been configured or not. 178 * <p/> 179 * Can be used to test if none has been configured and then install a custom error handler builder 180 * replacing the default error handler (that would have been used as fallback otherwise). 181 * <br/> 182 * This is for instance used by the transacted policy to setup a TransactedErrorHandlerBuilder 183 * in camel-spring. 184 */ 185 public static boolean isErrorHandlerBuilderConfigured(String ref) { 186 return !DEFAULT_ERROR_HANDLER_BUILDER.equals(ref); 187 } 188 189 public String getRef() { 190 return ref; 191 } 192 193 private ErrorHandlerBuilder createErrorHandler(RouteContext routeContext) { 194 ErrorHandlerBuilder handler = (ErrorHandlerBuilder)lookupErrorHandlerBuilder(routeContext, getRef()); 195 ObjectHelper.notNull(handler, "error handler '" + ref + "'"); 196 197 // configure if the handler support transacted 198 supportTransacted = handler.supportTransacted(); 199 200 List<OnExceptionDefinition> list = getErrorHandlers(routeContext); 201 if (list != null) { 202 for (OnExceptionDefinition exceptionType : list) { 203 handler.addErrorHandlers(routeContext, exceptionType); 204 } 205 } 206 return handler; 207 } 208 209 @Override 210 public String toString() { 211 return "ErrorHandlerBuilderRef[" + ref + "]"; 212 } 213}