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 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 }