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.spi.RouteContext;
025    import org.apache.camel.spi.TransactedPolicy;
026    import org.apache.camel.util.CamelLogger;
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        private LoggingLevel rollbackLoggingLevel = LoggingLevel.WARN;
044    
045        public TransactionErrorHandlerBuilder() {
046            // no-arg constructor used by Spring DSL
047        }
048    
049        public TransactionTemplate getTransactionTemplate() {
050            return transactionTemplate;
051        }
052    
053        public boolean supportTransacted() {
054            return true;
055        }
056    
057        public Processor createErrorHandler(RouteContext routeContext, Processor processor) throws Exception {
058            if (transactionTemplate == null) {
059                // lookup in context if no transaction template has been configured
060                LOG.debug("No TransactionTemplate configured on TransactionErrorHandlerBuilder. Will try find it in the registry.");
061    
062                Map<String, TransactedPolicy> mapPolicy = routeContext.lookupByType(TransactedPolicy.class);
063                if (mapPolicy != null && mapPolicy.size() == 1) {
064                    TransactedPolicy policy = mapPolicy.values().iterator().next();
065                    if (policy != null && policy instanceof SpringTransactionPolicy) {
066                        transactionTemplate = ((SpringTransactionPolicy) policy).getTransactionTemplate();
067                    }
068                }
069    
070                if (transactionTemplate == null) {
071                    TransactedPolicy policy = routeContext.lookup(PROPAGATION_REQUIRED, TransactedPolicy.class);
072                    if (policy != null && policy instanceof SpringTransactionPolicy) {
073                        transactionTemplate = ((SpringTransactionPolicy) policy).getTransactionTemplate();
074                    }
075                }
076    
077                if (transactionTemplate == null) {
078                    Map<String, TransactionTemplate> mapTemplate = routeContext.lookupByType(TransactionTemplate.class);
079                    if (mapTemplate != null && mapTemplate.size() == 1) {
080                        transactionTemplate = mapTemplate.values().iterator().next();
081                    }
082                    if (mapTemplate == null || mapTemplate.isEmpty()) {
083                        LOG.trace("No TransactionTemplate found in registry.");
084                    } else {
085                        LOG.debug("Found {} TransactionTemplate in registry. Cannot determine which one to use. "
086                                  + "Please configure a TransactionTemplate on the TransactionErrorHandlerBuilder", mapTemplate.size());
087                    }
088                }
089    
090                if (transactionTemplate == null) {
091                    Map<String, PlatformTransactionManager> mapManager = routeContext.lookupByType(PlatformTransactionManager.class);
092                    if (mapManager != null && mapManager.size() == 1) {
093                        transactionTemplate = new TransactionTemplate(mapManager.values().iterator().next());
094                    }
095                    if (mapManager == null || mapManager.isEmpty()) {
096                        LOG.trace("No PlatformTransactionManager found in registry.");
097                    } else {
098                        LOG.debug("Found {} PlatformTransactionManager in registry. Cannot determine which one to use for TransactionTemplate. "
099                                  + "Please configure a TransactionTemplate on the TransactionErrorHandlerBuilder", mapManager.size());
100                    }
101                }
102    
103                if (transactionTemplate != null) {
104                    LOG.debug("Found TransactionTemplate in registry to use: " + transactionTemplate);
105                }
106            }
107    
108            ObjectHelper.notNull(transactionTemplate, "transactionTemplate", this);
109    
110            TransactionErrorHandler answer = new TransactionErrorHandler(routeContext.getCamelContext(), processor,
111                getLogger(), getOnRedelivery(), getRedeliveryPolicy(), getExceptionPolicyStrategy(), transactionTemplate, 
112                getRetryWhilePolicy(routeContext.getCamelContext()), getExecutorService(routeContext.getCamelContext()), getRollbackLoggingLevel());
113            // configure error handler before we can use it
114            configure(routeContext, answer);
115            return answer;
116        }
117    
118        public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
119            this.transactionTemplate = transactionTemplate;
120        }
121    
122        public void setSpringTransactionPolicy(SpringTransactionPolicy policy) {
123            this.transactionTemplate = policy.getTransactionTemplate();
124        }
125    
126        public void setTransactionManager(PlatformTransactionManager transactionManager) {
127            this.transactionTemplate = new TransactionTemplate(transactionManager);
128        }
129    
130        public LoggingLevel getRollbackLoggingLevel() {
131            return rollbackLoggingLevel;
132        }
133    
134        /**
135         * Sets the logging level to use for logging transactional rollback.
136         * <p/>
137         * This option is default WARN.
138         *
139         * @param rollbackLoggingLevel the logging level
140         */
141        public void setRollbackLoggingLevel(LoggingLevel rollbackLoggingLevel) {
142            this.rollbackLoggingLevel = rollbackLoggingLevel;
143        }
144    
145        // Builder methods
146        // -------------------------------------------------------------------------
147    
148        /**
149         * Sets the logging level to use for logging transactional rollback.
150         * <p/>
151         * This option is default WARN.
152         *
153         * @param rollbackLoggingLevel the logging level
154         */
155        public TransactionErrorHandlerBuilder rollbackLoggingLevel(LoggingLevel rollbackLoggingLevel) {
156            setRollbackLoggingLevel(rollbackLoggingLevel);
157            return this;
158        }
159    
160        // Implementation
161        // -------------------------------------------------------------------------
162    
163        protected CamelLogger createLogger() {
164            return new CamelLogger(LoggerFactory.getLogger(TransactionErrorHandler.class), LoggingLevel.ERROR);
165        }
166    
167        @Override
168        public String toString() {
169            return "TransactionErrorHandlerBuilder";
170        }
171    
172    }