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<RouteContext, ErrorHandlerBuilder>(); 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 ErrorHandlerFactory answer; 103 104 // if the ref is the default then we do not have any explicit error handler configured 105 // if that is the case then use error handlers configured on the route, as for instance 106 // the transacted error handler could have been configured on the route so we should use that one 107 if (!isErrorHandlerBuilderConfigured(ref)) { 108 // see if there has been configured a route builder on the route 109 answer = routeContext.getRoute().getErrorHandlerBuilder(); 110 if (answer == null && routeContext.getRoute().getErrorHandlerRef() != null) { 111 answer = routeContext.lookup(routeContext.getRoute().getErrorHandlerRef(), ErrorHandlerBuilder.class); 112 } 113 if (answer == null) { 114 // fallback to the default error handler if none configured on the route 115 answer = new DefaultErrorHandlerBuilder(); 116 } 117 // check if its also a ref with no error handler configuration like me 118 if (answer instanceof ErrorHandlerBuilderRef) { 119 ErrorHandlerBuilderRef other = (ErrorHandlerBuilderRef) answer; 120 String otherRef = other.getRef(); 121 if (!isErrorHandlerBuilderConfigured(otherRef)) { 122 // the other has also no explicit error handler configured then fallback to the handler 123 // configured on the parent camel context 124 answer = lookupErrorHandlerBuilder((ModelCamelContext)routeContext.getCamelContext()); 125 } 126 if (answer == null) { 127 // the other has also no explicit error handler configured then fallback to the default error handler 128 // otherwise we could recursive loop forever (triggered by createErrorHandler method) 129 answer = new DefaultErrorHandlerBuilder(); 130 } 131 // inherit the error handlers from the other as they are to be shared 132 // this is needed by camel-spring when none error handler has been explicit configured 133 ((ErrorHandlerBuilder)answer).setErrorHandlers(routeContext, other.getErrorHandlers(routeContext)); 134 } 135 } else { 136 // use specific configured error handler 137 answer = routeContext.mandatoryLookup(ref, ErrorHandlerBuilder.class); 138 } 139 140 return answer; 141 } 142 143 protected static ErrorHandlerFactory lookupErrorHandlerBuilder(ModelCamelContext camelContext) { 144 @SuppressWarnings("deprecation") 145 ErrorHandlerFactory answer = camelContext.getErrorHandlerBuilder(); 146 if (answer instanceof ErrorHandlerBuilderRef) { 147 ErrorHandlerBuilderRef other = (ErrorHandlerBuilderRef) answer; 148 String otherRef = other.getRef(); 149 if (isErrorHandlerBuilderConfigured(otherRef)) { 150 answer = camelContext.getRegistry().lookupByNameAndType(otherRef, ErrorHandlerBuilder.class); 151 if (answer == null) { 152 throw new IllegalArgumentException("ErrorHandlerBuilder with id " + otherRef + " not found in registry."); 153 } 154 } 155 } 156 157 return answer; 158 } 159 160 /** 161 * Returns whether a specific error handler builder has been configured or not. 162 * <p/> 163 * Can be used to test if none has been configured and then install a custom error handler builder 164 * replacing the default error handler (that would have been used as fallback otherwise). 165 * <br/> 166 * This is for instance used by the transacted policy to setup a TransactedErrorHandlerBuilder 167 * in camel-spring. 168 */ 169 public static boolean isErrorHandlerBuilderConfigured(String ref) { 170 return !DEFAULT_ERROR_HANDLER_BUILDER.equals(ref); 171 } 172 173 public String getRef() { 174 return ref; 175 } 176 177 private ErrorHandlerBuilder createErrorHandler(RouteContext routeContext) { 178 ErrorHandlerBuilder handler = (ErrorHandlerBuilder)lookupErrorHandlerBuilder(routeContext, getRef()); 179 ObjectHelper.notNull(handler, "error handler '" + ref + "'"); 180 181 // configure if the handler support transacted 182 supportTransacted = handler.supportTransacted(); 183 184 List<OnExceptionDefinition> list = getErrorHandlers(routeContext); 185 if (list != null) { 186 for (OnExceptionDefinition exceptionType : list) { 187 handler.addErrorHandlers(routeContext, exceptionType); 188 } 189 } 190 return handler; 191 } 192 193 @Override 194 public String toString() { 195 return "ErrorHandlerBuilderRef[" + ref + "]"; 196 } 197}