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