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