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.spring.spi;
018    
019    import java.util.Map;
020    
021    import org.apache.camel.LoggingLevel;
022    import org.apache.camel.Processor;
023    import org.apache.camel.builder.DefaultErrorHandlerBuilder;
024    import org.apache.camel.processor.Logger;
025    import org.apache.camel.spi.RouteContext;
026    import org.apache.camel.spi.TransactedPolicy;
027    import org.apache.camel.util.ObjectHelper;
028    import org.apache.commons.logging.Log;
029    import org.apache.commons.logging.LogFactory;
030    import org.springframework.transaction.PlatformTransactionManager;
031    import org.springframework.transaction.support.TransactionTemplate;
032    
033    /**
034     * A transactional error handler that supports leveraging Spring TransactionManager.
035     *
036     * @version $Revision: 785080 $
037     */
038    public class TransactionErrorHandlerBuilder extends DefaultErrorHandlerBuilder {
039    
040        private static final transient Log LOG = LogFactory.getLog(TransactionErrorHandlerBuilder.class);
041        private static final String PROPAGATION_REQUIRED = "PROPAGATION_REQUIRED";
042        private TransactionTemplate transactionTemplate;
043    
044        public TransactionErrorHandlerBuilder() {
045            // no-arg constructor used by Spring DSL
046        }
047    
048        public TransactionTemplate getTransactionTemplate() {
049            return transactionTemplate;
050        }
051    
052        public boolean supportTransacted() {
053            return true;
054        }
055    
056        public Processor createErrorHandler(RouteContext routeContext, Processor processor) throws Exception {
057            if (transactionTemplate == null) {
058                // lookup in context if no transaction template has been configured
059                LOG.debug("No TransactionTemplate configured on TransactionErrorHandlerBuilder. Will try find it in the registry.");
060    
061                if (transactionTemplate == null) {
062                    Map<String, TransactedPolicy> map = routeContext.lookupByType(TransactedPolicy.class);
063                    if (map != null && map.size() == 1) {
064                        TransactedPolicy policy = map.values().iterator().next();
065                        if (policy != null && policy instanceof SpringTransactionPolicy) {
066                            transactionTemplate = ((SpringTransactionPolicy) policy).getTransactionTemplate();
067                        }
068                    }
069                }
070    
071                if (transactionTemplate == null) {
072                    TransactedPolicy policy = routeContext.lookup(PROPAGATION_REQUIRED, TransactedPolicy.class);
073                    if (policy != null && policy instanceof SpringTransactionPolicy) {
074                        transactionTemplate = ((SpringTransactionPolicy) policy).getTransactionTemplate();
075                    }
076                }
077    
078                if (transactionTemplate == null) {
079                    Map<String, TransactionTemplate> map = routeContext.lookupByType(TransactionTemplate.class);
080                    if (map != null && map.size() == 1) {
081                        transactionTemplate = map.values().iterator().next();
082                    } else if (LOG.isDebugEnabled()) {
083                        if (map == null || map.isEmpty()) {
084                            LOG.trace("No TransactionTemplate found in registry.");
085                        } else {
086                            LOG.debug("Found " + map.size() + " TransactionTemplate in registry. "
087                                    + "Cannot determine which one to use. Please configure a TransactionTemplate on the TransactionErrorHandlerBuilder");
088                        }
089                    }
090                }
091    
092                if (transactionTemplate == null) {
093                    Map<String, PlatformTransactionManager> map = routeContext.lookupByType(PlatformTransactionManager.class);
094                    if (map != null && map.size() == 1) {
095                        transactionTemplate = new TransactionTemplate(map.values().iterator().next());
096                    } else if (LOG.isDebugEnabled()) {
097                        if (map == null || map.isEmpty()) {
098                            LOG.trace("No PlatformTransactionManager found in registry.");
099                        } else {
100                            LOG.debug("Found " + map.size() + " PlatformTransactionManager in registry. "
101                                    + "Cannot determine which one to use for TransactionTemplate. Please configure a TransactionTemplate on the TransactionErrorHandlerBuilder");
102                        }
103                    }
104                }
105    
106                if (transactionTemplate != null) {
107                    LOG.debug("Found TransactionTemplate in registry to use: " + transactionTemplate);
108                }
109            }
110    
111            ObjectHelper.notNull(transactionTemplate, "transactionTemplate", this);
112    
113            TransactionErrorHandler answer = new TransactionErrorHandler(processor, getLogger(), getOnRedelivery(),
114                    getRedeliveryPolicy(), getHandledPolicy(), getExceptionPolicyStrategy(), transactionTemplate);
115            // configure error handler before we can use it
116            configure(answer);
117            return answer;
118        }
119    
120        public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
121            this.transactionTemplate = transactionTemplate;
122        }
123    
124        public void setSpringTransactionPolicy(SpringTransactionPolicy policy) {
125            this.transactionTemplate = policy.getTransactionTemplate();
126        }
127    
128        // Builder methods
129        // -------------------------------------------------------------------------
130    
131        protected Logger createLogger() {
132            return new Logger(LogFactory.getLog(TransactionErrorHandler.class), LoggingLevel.ERROR);
133        }
134    
135        @Override
136        public String toString() {
137            return "TransactionErrorHandlerBuilder";
138        }
139    
140    }