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.CamelLogger;
025    import org.apache.camel.spi.RouteContext;
026    import org.apache.camel.spi.TransactedPolicy;
027    import org.apache.camel.util.ObjectHelper;
028    import org.slf4j.Logger;
029    import org.slf4j.LoggerFactory;
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 
037     */
038    public class TransactionErrorHandlerBuilder extends DefaultErrorHandlerBuilder {
039    
040        private static final transient Logger LOG = LoggerFactory.getLogger(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                Map<String, TransactedPolicy> mapPolicy = routeContext.lookupByType(TransactedPolicy.class);
062                if (mapPolicy != null && mapPolicy.size() == 1) {
063                    TransactedPolicy policy = mapPolicy.values().iterator().next();
064                    if (policy != null && policy instanceof SpringTransactionPolicy) {
065                        transactionTemplate = ((SpringTransactionPolicy) policy).getTransactionTemplate();
066                    }
067                }
068    
069                if (transactionTemplate == null) {
070                    TransactedPolicy policy = routeContext.lookup(PROPAGATION_REQUIRED, TransactedPolicy.class);
071                    if (policy != null && policy instanceof SpringTransactionPolicy) {
072                        transactionTemplate = ((SpringTransactionPolicy) policy).getTransactionTemplate();
073                    }
074                }
075    
076                if (transactionTemplate == null) {
077                    Map<String, TransactionTemplate> mapTemplate = routeContext.lookupByType(TransactionTemplate.class);
078                    if (mapTemplate != null && mapTemplate.size() == 1) {
079                        transactionTemplate = mapTemplate.values().iterator().next();
080                    }
081                    if (mapTemplate == null || mapTemplate.isEmpty()) {
082                        LOG.trace("No TransactionTemplate found in registry.");
083                    } else {
084                        LOG.debug("Found {} TransactionTemplate in registry. Cannot determine which one to use. "
085                                  + "Please configure a TransactionTemplate on the TransactionErrorHandlerBuilder", mapTemplate.size());
086                    }
087                }
088    
089                if (transactionTemplate == null) {
090                    Map<String, PlatformTransactionManager> mapManager = routeContext.lookupByType(PlatformTransactionManager.class);
091                    if (mapManager != null && mapManager.size() == 1) {
092                        transactionTemplate = new TransactionTemplate(mapManager.values().iterator().next());
093                    }
094                    if (mapManager == null || mapManager.isEmpty()) {
095                        LOG.trace("No PlatformTransactionManager found in registry.");
096                    } else {
097                        LOG.debug("Found {} PlatformTransactionManager in registry. Cannot determine which one to use for TransactionTemplate. "
098                                  + "Please configure a TransactionTemplate on the TransactionErrorHandlerBuilder", mapManager.size());
099                    }
100                }
101    
102                if (transactionTemplate != null) {
103                    LOG.debug("Found TransactionTemplate in registry to use: " + transactionTemplate);
104                }
105            }
106    
107            ObjectHelper.notNull(transactionTemplate, "transactionTemplate", this);
108    
109            TransactionErrorHandler answer = new TransactionErrorHandler(routeContext.getCamelContext(), processor,
110                getLogger(), getOnRedelivery(), getRedeliveryPolicy(), getExceptionPolicyStrategy(), transactionTemplate, 
111                getRetryWhilePolicy(routeContext.getCamelContext()), getExecutorServiceRef());
112            // configure error handler before we can use it
113            configure(answer);
114            return answer;
115        }
116    
117        public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
118            this.transactionTemplate = transactionTemplate;
119        }
120    
121        public void setSpringTransactionPolicy(SpringTransactionPolicy policy) {
122            this.transactionTemplate = policy.getTransactionTemplate();
123        }
124    
125        public void setTransactionManager(PlatformTransactionManager transactionManager) {
126            this.transactionTemplate = new TransactionTemplate(transactionManager);
127        }
128    
129        // Builder methods
130        // -------------------------------------------------------------------------
131    
132        protected CamelLogger createLogger() {
133            return new CamelLogger(LoggerFactory.getLogger(TransactionErrorHandler.class), LoggingLevel.ERROR);
134        }
135    
136        @Override
137        public String toString() {
138            return "TransactionErrorHandlerBuilder";
139        }
140    
141    }