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.CamelContext; 023import org.apache.camel.NoSuchBeanException; 024import org.apache.camel.Route; 025import org.apache.camel.RuntimeCamelException; 026import org.apache.camel.model.ProcessorDefinition; 027import org.apache.camel.spi.Policy; 028import org.apache.camel.spi.TransactedPolicy; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032import static org.apache.camel.model.TransactedDefinition.PROPAGATION_REQUIRED; 033 034public abstract class AbstractPolicyReifier<T extends ProcessorDefinition<?>> extends ProcessorReifier<T> { 035 036 private static final Logger LOG = LoggerFactory.getLogger(TransactedReifier.class); 037 038 public AbstractPolicyReifier(Route route, T definition) { 039 super(route, definition); 040 } 041 042 public AbstractPolicyReifier(CamelContext camelContext, T definition) { 043 super(camelContext, definition); 044 } 045 046 public Policy resolvePolicy(Policy policy, String ref, Class<? extends Policy> type) { 047 if (policy != null) { 048 return policy; 049 } 050 // explicit ref given so lookup by it 051 if (org.apache.camel.util.ObjectHelper.isNotEmpty(ref)) { 052 return mandatoryLookup(ref, Policy.class); 053 } 054 055 // no explicit reference given from user so we can use some convention 056 // over configuration here 057 058 // try to lookup by scoped type 059 Policy answer = null; 060 if (type != null) { 061 // try find by type, note that this method is not supported by all 062 // registry 063 Map<String, ?> types = findByTypeWithName(type); 064 if (types.size() == 1) { 065 // only one policy defined so use it 066 Object found = types.values().iterator().next(); 067 if (type.isInstance(found)) { 068 return type.cast(found); 069 } 070 } 071 } 072 073 // for transacted routing try the default REQUIRED name 074 if (type == TransactedPolicy.class) { 075 // still not found try with the default name PROPAGATION_REQUIRED 076 answer = lookup(PROPAGATION_REQUIRED, TransactedPolicy.class); 077 } 078 079 // this logic only applies if we are a transacted policy 080 // still no policy found then try lookup the platform transaction 081 // manager and use it as policy 082 if (answer == null && type == TransactedPolicy.class) { 083 Class<?> tmClazz = camelContext.getClassResolver().resolveClass("org.springframework.transaction.PlatformTransactionManager"); 084 if (tmClazz != null) { 085 // see if we can find the platform transaction manager in the 086 // registry 087 Map<String, ?> maps = findByTypeWithName(tmClazz); 088 if (maps.size() == 1) { 089 // only one platform manager then use it as default and 090 // create a transacted 091 // policy with it and default to required 092 093 // as we do not want dependency on spring jars in the 094 // camel-core we use 095 // reflection to lookup classes and create new objects and 096 // call methods 097 // as this is only done during route building it does not 098 // matter that we 099 // use reflection as performance is no a concern during 100 // route building 101 Object transactionManager = maps.values().iterator().next(); 102 LOG.debug("One instance of PlatformTransactionManager found in registry: {}", transactionManager); 103 Class<?> txClazz = camelContext.getClassResolver().resolveClass("org.apache.camel.spring.spi.SpringTransactionPolicy"); 104 if (txClazz != null) { 105 LOG.debug("Creating a new temporary SpringTransactionPolicy using the PlatformTransactionManager: {}", transactionManager); 106 TransactedPolicy txPolicy = org.apache.camel.support.ObjectHelper.newInstance(txClazz, TransactedPolicy.class); 107 Method method; 108 try { 109 method = txClazz.getMethod("setTransactionManager", tmClazz); 110 } catch (NoSuchMethodException e) { 111 throw new RuntimeCamelException("Cannot get method setTransactionManager(PlatformTransactionManager) on class: " + txClazz); 112 } 113 org.apache.camel.support.ObjectHelper.invokeMethod(method, txPolicy, transactionManager); 114 return txPolicy; 115 } else { 116 // camel-spring is missing on the classpath 117 throw new RuntimeCamelException("Cannot create a transacted policy as camel-spring.jar is not on the classpath!"); 118 } 119 } else { 120 if (maps.isEmpty()) { 121 throw new NoSuchBeanException(null, "PlatformTransactionManager"); 122 } else { 123 throw new IllegalArgumentException("Found " + maps.size() + " PlatformTransactionManager in registry. " 124 + "Cannot determine which one to use. Please configure a TransactionTemplate on the transacted policy."); 125 } 126 } 127 } 128 } 129 130 return answer; 131 } 132}