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    }