1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.transaction.interceptor;
  17. import java.lang.reflect.Method;
  18. import java.util.HashMap;
  19. import java.util.Iterator;
  20. import java.util.Map;
  21. import java.util.Properties;
  22. import org.apache.commons.logging.Log;
  23. import org.apache.commons.logging.LogFactory;
  24. /**
  25. * Simple implementation of TransactionAttributeSource that
  26. * allows attributes to be matched by registered name.
  27. * @author Juergen Hoeller
  28. * @since 21.08.2003
  29. * @see #isMatch
  30. */
  31. public class NameMatchTransactionAttributeSource implements TransactionAttributeSource {
  32. protected final Log logger = LogFactory.getLog(getClass());
  33. private Map nameMap = new HashMap();
  34. /**
  35. * Set a name/attribute map, consisting of method names
  36. * (e.g. "myMethod") and TransactionAttribute instances.
  37. * @see TransactionAttribute
  38. */
  39. public void setNameMap(Map nameMap) {
  40. this.nameMap = nameMap;
  41. }
  42. /**
  43. * Parses the given properties into a name/attribute map.
  44. * Expects method names as keys and String attributes definitions as values,
  45. * parsable into TransactionAttribute instances via TransactionAttributeEditor.
  46. * @see #setNameMap
  47. * @see TransactionAttributeEditor
  48. */
  49. public void setProperties(Properties transactionAttributes) {
  50. TransactionAttributeEditor tae = new TransactionAttributeEditor();
  51. for (Iterator it = transactionAttributes.keySet().iterator(); it.hasNext(); ) {
  52. String methodName = (String) it.next();
  53. String value = transactionAttributes.getProperty(methodName);
  54. tae.setAsText(value);
  55. TransactionAttribute attr = (TransactionAttribute) tae.getValue();
  56. addTransactionalMethod(methodName, attr);
  57. }
  58. }
  59. /**
  60. * Add an attribute for a transactional method.
  61. * Method names can end with "*" for matching multiple methods.
  62. * @param methodName the name of the method
  63. * @param attr attribute associated with the method
  64. */
  65. public void addTransactionalMethod(String methodName, TransactionAttribute attr) {
  66. logger.debug("Adding transactional method [" + methodName + "] with attribute [" + attr + "]");
  67. this.nameMap.put(methodName, attr);
  68. }
  69. public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) {
  70. String methodName = method.getName();
  71. TransactionAttribute attr = (TransactionAttribute) this.nameMap.get(methodName);
  72. if (attr != null) {
  73. return attr;
  74. }
  75. else {
  76. // look up most specific name match
  77. String bestNameMatch = null;
  78. for (Iterator it = this.nameMap.keySet().iterator(); it.hasNext();) {
  79. String mappedName = (String) it.next();
  80. if (isMatch(methodName, mappedName) &&
  81. (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
  82. attr = (TransactionAttribute) this.nameMap.get(mappedName);
  83. bestNameMatch = mappedName;
  84. }
  85. }
  86. return attr;
  87. }
  88. }
  89. /**
  90. * Return if the given method name matches the mapped name.
  91. * The default implementation checks for "xxx*" and "*xxx" matches.
  92. * Can be overridden in subclasses.
  93. * @param methodName the method name of the class
  94. * @param mappedName the name in the descriptor
  95. * @return if the names match
  96. */
  97. protected boolean isMatch(String methodName, String mappedName) {
  98. return (mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1))) ||
  99. (mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
  100. }
  101. }