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 */ 017package org.apache.camel.reifier; 018 019import java.lang.reflect.Method; 020import java.util.Map; 021 022import org.apache.camel.NoSuchBeanException; 023import org.apache.camel.Processor; 024import org.apache.camel.RuntimeCamelException; 025import org.apache.camel.Service; 026import org.apache.camel.model.ProcessorDefinition; 027import org.apache.camel.model.TransactedDefinition; 028import org.apache.camel.processor.WrapProcessor; 029import org.apache.camel.spi.Policy; 030import org.apache.camel.spi.RouteContext; 031import org.apache.camel.spi.TransactedPolicy; 032import org.apache.camel.support.CamelContextHelper; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036import static org.apache.camel.model.TransactedDefinition.PROPAGATION_REQUIRED; 037 038public class TransactedReifier extends ProcessorReifier<TransactedDefinition> { 039 040 private static final Logger LOG = LoggerFactory.getLogger(TransactedReifier.class); 041 042 public TransactedReifier(ProcessorDefinition<?> definition) { 043 super((TransactedDefinition)definition); 044 } 045 046 @Override 047 public Processor createProcessor(RouteContext routeContext) throws Exception { 048 Policy policy = resolvePolicy(routeContext); 049 org.apache.camel.util.ObjectHelper.notNull(policy, "policy", this); 050 051 // before wrap 052 policy.beforeWrap(routeContext, definition); 053 054 // create processor after the before wrap 055 Processor childProcessor = this.createChildProcessor(routeContext, true); 056 057 // wrap 058 Processor target = policy.wrap(routeContext, childProcessor); 059 060 if (!(target instanceof Service)) { 061 // wrap the target so it becomes a service and we can manage its 062 // lifecycle 063 target = new WrapProcessor(target, childProcessor); 064 } 065 return target; 066 } 067 068 protected Policy resolvePolicy(RouteContext routeContext) { 069 return resolvePolicy(routeContext, definition); 070 } 071 072 public static Policy resolvePolicy(RouteContext routeContext, TransactedDefinition definition) { 073 if (definition.getPolicy() != null) { 074 return definition.getPolicy(); 075 } 076 return resolvePolicy(routeContext, definition.getRef(), definition.getType()); 077 } 078 079 public static Policy resolvePolicy(RouteContext routeContext, String ref, Class<? extends Policy> type) { 080 // explicit ref given so lookup by it 081 if (org.apache.camel.util.ObjectHelper.isNotEmpty(ref)) { 082 return CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), ref, Policy.class); 083 } 084 085 // no explicit reference given from user so we can use some convention 086 // over configuration here 087 088 // try to lookup by scoped type 089 Policy answer = null; 090 if (type != null) { 091 // try find by type, note that this method is not supported by all 092 // registry 093 Map<String, ?> types = routeContext.lookupByType(type); 094 if (types.size() == 1) { 095 // only one policy defined so use it 096 Object found = types.values().iterator().next(); 097 if (type.isInstance(found)) { 098 return type.cast(found); 099 } 100 } 101 } 102 103 // for transacted routing try the default REQUIRED name 104 if (type == TransactedPolicy.class) { 105 // still not found try with the default name PROPAGATION_REQUIRED 106 answer = routeContext.lookup(PROPAGATION_REQUIRED, TransactedPolicy.class); 107 } 108 109 // this logic only applies if we are a transacted policy 110 // still no policy found then try lookup the platform transaction 111 // manager and use it as policy 112 if (answer == null && type == TransactedPolicy.class) { 113 Class<?> tmClazz = routeContext.getCamelContext().getClassResolver().resolveClass("org.springframework.transaction.PlatformTransactionManager"); 114 if (tmClazz != null) { 115 // see if we can find the platform transaction manager in the 116 // registry 117 Map<String, ?> maps = routeContext.lookupByType(tmClazz); 118 if (maps.size() == 1) { 119 // only one platform manager then use it as default and 120 // create a transacted 121 // policy with it and default to required 122 123 // as we do not want dependency on spring jars in the 124 // camel-core we use 125 // reflection to lookup classes and create new objects and 126 // call methods 127 // as this is only done during route building it does not 128 // matter that we 129 // use reflection as performance is no a concern during 130 // route building 131 Object transactionManager = maps.values().iterator().next(); 132 LOG.debug("One instance of PlatformTransactionManager found in registry: {}", transactionManager); 133 Class<?> txClazz = routeContext.getCamelContext().getClassResolver().resolveClass("org.apache.camel.spring.spi.SpringTransactionPolicy"); 134 if (txClazz != null) { 135 LOG.debug("Creating a new temporary SpringTransactionPolicy using the PlatformTransactionManager: {}", transactionManager); 136 TransactedPolicy txPolicy = org.apache.camel.support.ObjectHelper.newInstance(txClazz, TransactedPolicy.class); 137 Method method; 138 try { 139 method = txClazz.getMethod("setTransactionManager", tmClazz); 140 } catch (NoSuchMethodException e) { 141 throw new RuntimeCamelException("Cannot get method setTransactionManager(PlatformTransactionManager) on class: " + txClazz); 142 } 143 org.apache.camel.support.ObjectHelper.invokeMethod(method, txPolicy, transactionManager); 144 return txPolicy; 145 } else { 146 // camel-spring is missing on the classpath 147 throw new RuntimeCamelException("Cannot create a transacted policy as camel-spring.jar is not on the classpath!"); 148 } 149 } else { 150 if (maps.isEmpty()) { 151 throw new NoSuchBeanException(null, "PlatformTransactionManager"); 152 } else { 153 throw new IllegalArgumentException("Found " + maps.size() + " PlatformTransactionManager in registry. " 154 + "Cannot determine which one to use. Please configure a TransactionTemplate on the transacted policy."); 155 } 156 } 157 } 158 } 159 160 return answer; 161 } 162}