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