1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  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.apache.commons.attributes;
  17. import java.lang.reflect.Field;
  18. import java.lang.reflect.Constructor;
  19. import java.lang.reflect.Method;
  20. import java.lang.reflect.Modifier;
  21. import java.util.ArrayList;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.Iterator;
  25. import java.util.List;
  26. import java.util.Map;
  27. import java.util.Set;
  28. import java.util.HashSet;
  29. import java.util.HashMap;
  30. class DefaultCachedRepository implements CachedRepository {
  31. private final static Collection EMPTY_COLLECTION = new ArrayList (0);
  32. private final Collection classAttributes;
  33. private final Map fields = new HashMap ();
  34. private final Map methods = new HashMap ();
  35. private final Map constructors = new HashMap ();
  36. private static class MethodAttributeBundle {
  37. private Collection attributes = EMPTY_COLLECTION;
  38. private List parameterAttributes = new ArrayList ();
  39. private Collection returnAttributes = EMPTY_COLLECTION;
  40. public MethodAttributeBundle () {
  41. }
  42. public Collection getAttributes () {
  43. return attributes;
  44. }
  45. public Collection getReturnAttributes () {
  46. return returnAttributes;
  47. }
  48. public Collection getParameterAttributes (int index) {
  49. return (Collection) parameterAttributes.get (index);
  50. }
  51. public void setAttributes (Collection attributes) {
  52. this.attributes = Collections.unmodifiableCollection (attributes);
  53. }
  54. public void setReturnAttributes (Collection returnAttributes) {
  55. this.returnAttributes = Collections.unmodifiableCollection (returnAttributes);
  56. }
  57. public void addParameterAttributes (Collection parameterAttributes) {
  58. this.parameterAttributes.add (Collections.unmodifiableCollection (parameterAttributes));
  59. }
  60. }
  61. public DefaultCachedRepository (Class clazz, AttributeRepositoryClass repo) {
  62. // ---- Fix up class attributes
  63. Set tempClassAttributes = new HashSet ();
  64. tempClassAttributes.addAll (repo.getClassAttributes ());
  65. tempClassAttributes.addAll (getInheritableClassAttributes (clazz.getSuperclass ()));
  66. Class[] ifs = clazz.getInterfaces ();
  67. for (int i = 0; i < ifs.length; i++) {
  68. tempClassAttributes.addAll (getInheritableClassAttributes (ifs[i]));
  69. }
  70. this.classAttributes = Collections.unmodifiableCollection (tempClassAttributes);
  71. // ---- Fix up method attributes
  72. Method[] methods = clazz.getDeclaredMethods ();
  73. for (int i = 0; i < methods.length; i++) {
  74. MethodAttributeBundle bundle = new MethodAttributeBundle ();
  75. Method m = methods[i];
  76. String key = Util.getSignature (m);
  77. List attributeBundle = null;
  78. if (repo.getMethodAttributes ().containsKey (key)) {
  79. attributeBundle = (List) repo.getMethodAttributes ().get (key);
  80. }
  81. Set attributes = new HashSet ();
  82. if (attributeBundle != null) {
  83. attributes.addAll ((Collection) attributeBundle.get (0));
  84. }
  85. attributes.addAll (getInheritableMethodAttributes (clazz.getSuperclass (), m.getName (), m.getParameterTypes ()));
  86. for (int j = 0; j < ifs.length; j++) {
  87. attributes.addAll (getInheritableMethodAttributes (ifs[j], m.getName (), m.getParameterTypes ()));
  88. }
  89. if (attributes.size () > 0) {
  90. bundle.setAttributes (attributes);
  91. }
  92. // ---- Return value attributes
  93. attributes = new HashSet ();
  94. if (attributeBundle != null) {
  95. attributes.addAll ((Collection) attributeBundle.get (1));
  96. }
  97. attributes.addAll (getInheritableReturnAttributes (clazz.getSuperclass (), m.getName (), m.getParameterTypes ()));
  98. for (int j = 0; j < ifs.length; j++) {
  99. attributes.addAll (getInheritableReturnAttributes (ifs[j], m.getName (), m.getParameterTypes ()));
  100. }
  101. if (attributes.size () > 0) {
  102. bundle.setReturnAttributes (attributes);
  103. }
  104. // ---- Parameter attributes
  105. int numParameters = m.getParameterTypes().length;
  106. for (int k = 0; k < numParameters; k++) {
  107. attributes = new HashSet ();
  108. if (attributeBundle != null) {
  109. attributes.addAll ((Collection) attributeBundle.get (k + 2));
  110. }
  111. attributes.addAll (getInheritableMethodParameterAttributes (clazz.getSuperclass (), m.getName (), m.getParameterTypes (), k));
  112. for (int j = 0; j < ifs.length; j++) {
  113. attributes.addAll (getInheritableMethodParameterAttributes (ifs[j], m.getName (), m.getParameterTypes (), k));
  114. }
  115. bundle.addParameterAttributes (attributes);
  116. }
  117. this.methods.put (m, bundle);
  118. }
  119. // --- Just copy constructor attributes (they aren't inherited)
  120. Constructor[] constructors = clazz.getDeclaredConstructors ();
  121. for (int i = 0; i < constructors.length; i++) {
  122. Constructor ctor = constructors[i];
  123. String key = Util.getSignature (ctor);
  124. if (repo.getConstructorAttributes ().containsKey (key)) {
  125. List attributeBundle = null;
  126. attributeBundle = (List) repo.getConstructorAttributes ().get (key);
  127. MethodAttributeBundle bundle = new MethodAttributeBundle ();
  128. bundle.setAttributes ((Collection) attributeBundle.get (0));
  129. // ---- Parameter attributes
  130. int numParameters = ctor.getParameterTypes().length;
  131. for (int k = 0; k < numParameters; k++) {
  132. bundle.addParameterAttributes ((Collection) attributeBundle.get (k + 1));
  133. }
  134. this.constructors.put (ctor, bundle);
  135. }
  136. }
  137. // --- Just copy field attributes (they aren't inherited)
  138. Field[] fields = clazz.getDeclaredFields ();
  139. for (int i = 0; i < fields.length; i++) {
  140. Field f = fields[i];
  141. String key = f.getName ();
  142. if (repo.getFieldAttributes ().containsKey (key)) {
  143. this.fields.put (f, Collections.unmodifiableCollection ((Collection) repo.getFieldAttributes ().get (key)));
  144. }
  145. }
  146. }
  147. private static Collection getInheritableAttributes (Collection attrs) {
  148. HashSet result = new HashSet ();
  149. Iterator iter = attrs.iterator ();
  150. while (iter.hasNext ()) {
  151. Object attr = iter.next ();
  152. if (Attributes.hasAttributeType (attr.getClass (), Inheritable.class)) {
  153. result.add (attr);
  154. }
  155. }
  156. return result;
  157. }
  158. private static Collection getInheritableClassAttributes (Class c) {
  159. if (c == null) {
  160. return new ArrayList (0);
  161. }
  162. HashSet result = new HashSet ();
  163. result.addAll (getInheritableAttributes (Attributes.getAttributes (c)));
  164. // Traverse the class hierarchy
  165. result.addAll (getInheritableClassAttributes (c.getSuperclass ()));
  166. // Traverse the interface hierarchy
  167. Class[] ifs = c.getInterfaces ();
  168. for (int i = 0; i < ifs.length; i++) {
  169. result.addAll (getInheritableClassAttributes (ifs[i]));
  170. }
  171. return result;
  172. }
  173. private static Collection getInheritableMethodAttributes (Class c, String methodName, Class[] methodParams) {
  174. if (c == null) {
  175. return new ArrayList (0);
  176. }
  177. HashSet result = new HashSet ();
  178. try {
  179. // Get equivalent method in c
  180. Method m = c.getDeclaredMethod (methodName, methodParams);
  181. if ((m.getModifiers () & Modifier.PRIVATE) == 0) {
  182. result.addAll (getInheritableAttributes (Attributes.getAttributes (m)));
  183. }
  184. } catch (NoSuchMethodException nsme) {
  185. }
  186. // Traverse the class hierarchy
  187. result.addAll (getInheritableMethodAttributes (c.getSuperclass (), methodName, methodParams));
  188. // Traverse the interface hierarchy
  189. Class[] ifs = c.getInterfaces ();
  190. for (int i = 0; i < ifs.length; i++) {
  191. result.addAll (getInheritableMethodAttributes (ifs[i], methodName, methodParams));
  192. }
  193. return result;
  194. }
  195. private static Collection getInheritableMethodParameterAttributes (Class c, String methodName, Class[] methodParams, int parameter) {
  196. if (c == null) {
  197. return new ArrayList (0);
  198. }
  199. HashSet result = new HashSet ();
  200. try {
  201. // Get equivalent method in c
  202. Method m = c.getDeclaredMethod (methodName, methodParams);
  203. if ((m.getModifiers () & Modifier.PRIVATE) == 0) {
  204. result.addAll (getInheritableAttributes (Attributes.getParameterAttributes (m, parameter)));
  205. }
  206. } catch (NoSuchMethodException nsme) {
  207. }
  208. // Traverse the class hierarchy
  209. result.addAll (getInheritableMethodParameterAttributes (c.getSuperclass (), methodName, methodParams, parameter));
  210. // Traverse the interface hierarchy
  211. Class[] ifs = c.getInterfaces ();
  212. for (int i = 0; i < ifs.length; i++) {
  213. result.addAll (getInheritableMethodParameterAttributes (ifs[i], methodName, methodParams, parameter));
  214. }
  215. return result;
  216. }
  217. private static Collection getInheritableReturnAttributes (Class c, String methodName, Class[] methodParams) {
  218. if (c == null) {
  219. return new ArrayList (0);
  220. }
  221. HashSet result = new HashSet ();
  222. try {
  223. // Get equivalent method in c
  224. Method m = c.getDeclaredMethod (methodName, methodParams);
  225. if ((m.getModifiers () & Modifier.PRIVATE) == 0) {
  226. result.addAll (getInheritableAttributes (Attributes.getReturnAttributes (m)));
  227. }
  228. } catch (NoSuchMethodException nsme) {
  229. }
  230. // Traverse the class hierarchy
  231. result.addAll (getInheritableReturnAttributes (c.getSuperclass (), methodName, methodParams));
  232. // Traverse the interface hierarchy
  233. Class[] ifs = c.getInterfaces ();
  234. for (int i = 0; i < ifs.length; i++) {
  235. result.addAll (getInheritableReturnAttributes (ifs[i], methodName, methodParams));
  236. }
  237. return result;
  238. }
  239. public Collection getAttributes () {
  240. return classAttributes;
  241. }
  242. public Collection getAttributes (Field f) {
  243. if (fields.containsKey (f)) {
  244. return (Collection) fields.get (f);
  245. } else {
  246. return EMPTY_COLLECTION;
  247. }
  248. }
  249. public Collection getAttributes (Method m) {
  250. if (methods.containsKey (m)) {
  251. return ((MethodAttributeBundle) methods.get (m)).getAttributes ();
  252. } else {
  253. return EMPTY_COLLECTION;
  254. }
  255. }
  256. public Collection getParameterAttributes (Constructor c, int parameter) {
  257. if (constructors.containsKey (c)) {
  258. return ((MethodAttributeBundle) constructors.get (c)).getParameterAttributes (parameter);
  259. } else {
  260. return EMPTY_COLLECTION;
  261. }
  262. }
  263. public Collection getParameterAttributes (Method m, int parameter) {
  264. if (methods.containsKey (m)) {
  265. return ((MethodAttributeBundle) methods.get (m)).getParameterAttributes (parameter);
  266. } else {
  267. return EMPTY_COLLECTION;
  268. }
  269. }
  270. public Collection getReturnAttributes (Method m) {
  271. if (methods.containsKey (m)) {
  272. return ((MethodAttributeBundle) methods.get (m)).getReturnAttributes ();
  273. } else {
  274. return EMPTY_COLLECTION;
  275. }
  276. }
  277. public Collection getAttributes (Constructor c) {
  278. if (constructors.containsKey (c)) {
  279. return ((MethodAttributeBundle) constructors.get (c)).getAttributes ();
  280. } else {
  281. return EMPTY_COLLECTION;
  282. }
  283. }
  284. }