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 }