1 16 17 package org.springframework.transaction.interceptor; 18 19 import java.lang.reflect.Method ; 20 import java.util.ArrayList ; 21 import java.util.HashMap ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Map ; 25 26 import org.apache.commons.logging.Log; 27 import org.apache.commons.logging.LogFactory; 28 29 import org.springframework.beans.factory.BeanClassLoaderAware; 30 import org.springframework.beans.factory.InitializingBean; 31 import org.springframework.util.Assert; 32 import org.springframework.util.ClassUtils; 33 import org.springframework.util.ObjectUtils; 34 import org.springframework.util.PatternMatchUtils; 35 36 46 public class MethodMapTransactionAttributeSource 47 implements TransactionAttributeSource, BeanClassLoaderAware, InitializingBean { 48 49 50 protected final Log logger = LogFactory.getLog(getClass()); 51 52 53 private Map methodMap; 54 55 private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); 56 57 private boolean eagerlyInitialized = false; 58 59 private boolean initialized = false; 60 61 62 private final Map transactionAttributeMap = new HashMap (); 63 64 65 private final Map methodNameMap = new HashMap (); 66 67 68 80 public void setMethodMap(Map methodMap) { 81 this.methodMap = methodMap; 82 } 83 84 public void setBeanClassLoader(ClassLoader beanClassLoader) { 85 this.beanClassLoader = beanClassLoader; 86 } 87 88 89 94 public void afterPropertiesSet() { 95 initMethodMap(this.methodMap); 96 this.eagerlyInitialized = true; 97 this.initialized = true; 98 } 99 100 106 protected void initMethodMap(Map methodMap) { 107 if (methodMap != null) { 108 Iterator it = methodMap.entrySet().iterator(); 109 while (it.hasNext()) { 110 Map.Entry entry = (Map.Entry ) it.next(); 111 Object key = entry.getKey(); 112 if (!(key instanceof String )) { 113 throw new IllegalArgumentException ( 114 "Invalid method map key [" + key + "]: only Strings allowed"); 115 } 116 Object value = entry.getValue(); 117 TransactionAttribute attr = null; 119 if (value instanceof TransactionAttribute) { 120 attr = (TransactionAttribute) value; 121 } 122 else if (value instanceof String ) { 123 TransactionAttributeEditor editor = new TransactionAttributeEditor(); 124 editor.setAsText((String ) value); 125 attr = (TransactionAttribute) editor.getValue(); 126 } 127 else { 128 throw new IllegalArgumentException ("Value [" + value + "] is neither of type [" + 129 TransactionAttribute.class.getName() + "] nor a String"); 130 } 131 addTransactionalMethod((String ) key, attr); 132 } 133 } 134 } 135 136 137 144 public void addTransactionalMethod(String name, TransactionAttribute attr) { 145 Assert.notNull(name, "Name must not be null"); 146 int lastDotIndex = name.lastIndexOf("."); 147 if (lastDotIndex == -1) { 148 throw new IllegalArgumentException ("'" + name + "' is not a valid method name: format is FQN.methodName"); 149 } 150 String className = name.substring(0, lastDotIndex); 151 String methodName = name.substring(lastDotIndex + 1); 152 Class clazz = ClassUtils.resolveClassName(className, this.beanClassLoader); 153 addTransactionalMethod(clazz, methodName, attr); 154 } 155 156 163 public void addTransactionalMethod(Class clazz, String mappedName, TransactionAttribute attr) { 164 Assert.notNull(clazz, "Class must not be null"); 165 Assert.notNull(mappedName, "Mapped name must not be null"); 166 String name = clazz.getName() + '.' + mappedName; 167 168 Method [] methods = clazz.getDeclaredMethods(); 172 List matchingMethods = new ArrayList (); 173 for (int i = 0; i < methods.length; i++) { 174 if (isMatch(methods[i].getName(), mappedName)) { 175 matchingMethods.add(methods[i]); 176 } 177 } 178 if (matchingMethods.isEmpty()) { 179 throw new IllegalArgumentException ( 180 "Couldn't find method '" + mappedName + "' on class [" + clazz.getName() + "]"); 181 } 182 183 for (Iterator it = matchingMethods.iterator(); it.hasNext();) { 185 Method method = (Method ) it.next(); 186 String regMethodName = (String ) this.methodNameMap.get(method); 187 if (regMethodName == null || (!regMethodName.equals(name) && regMethodName.length() <= name.length())) { 188 if (logger.isDebugEnabled() && regMethodName != null) { 191 logger.debug("Replacing attribute for transactional method [" + method + "]: current name '" + 192 name + "' is more specific than '" + regMethodName + "'"); 193 } 194 this.methodNameMap.put(method, name); 195 addTransactionalMethod(method, attr); 196 } 197 else { 198 if (logger.isDebugEnabled() && regMethodName != null) { 199 logger.debug("Keeping attribute for transactional method [" + method + "]: current name '" + 200 name + "' is not more specific than '" + regMethodName + "'"); 201 } 202 } 203 } 204 } 205 206 211 public void addTransactionalMethod(Method method, TransactionAttribute attr) { 212 Assert.notNull(method, "Method must not be null"); 213 Assert.notNull(attr, "TransactionAttribute must not be null"); 214 if (logger.isDebugEnabled()) { 215 logger.debug("Adding transactional method [" + method + "] with attribute [" + attr + "]"); 216 } 217 this.transactionAttributeMap.put(method, attr); 218 } 219 220 229 protected boolean isMatch(String methodName, String mappedName) { 230 return PatternMatchUtils.simpleMatch(mappedName, methodName); 231 } 232 233 234 public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) { 235 if (this.eagerlyInitialized) { 236 return (TransactionAttribute) this.transactionAttributeMap.get(method); 237 } 238 else { 239 synchronized (this.transactionAttributeMap) { 240 if (!this.initialized) { 241 initMethodMap(this.methodMap); 242 this.initialized = true; 243 } 244 return (TransactionAttribute) this.transactionAttributeMap.get(method); 245 } 246 } 247 } 248 249 250 public boolean equals(Object other) { 251 if (this == other) { 252 return true; 253 } 254 if (!(other instanceof MethodMapTransactionAttributeSource)) { 255 return false; 256 } 257 MethodMapTransactionAttributeSource otherTas = (MethodMapTransactionAttributeSource) other; 258 return ObjectUtils.nullSafeEquals(this.methodMap, otherTas.methodMap); 259 } 260 261 public int hashCode() { 262 return MethodMapTransactionAttributeSource.class.hashCode(); 263 } 264 265 public String toString() { 266 return getClass().getName() + ": " + this.methodMap; 267 } 268 269 } 270 | Popular Tags |