1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.jaxen;
5
6 import net.sourceforge.pmd.ast.Node;
7
8 import java.lang.reflect.Method;
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14
15 public class AttributeAxisIterator implements Iterator<Attribute> {
16
17 private static class MethodWrapper {
18 public Method method;
19 public String name;
20
21 public MethodWrapper(Method m) {
22 this.method = m;
23 this.name = truncateMethodName(m.getName());
24 }
25
26 private String truncateMethodName(String n) {
27
28 if (n.startsWith("get")) return n.substring("get".length());
29 if (n.startsWith("is")) return n.substring("is".length());
30 if (n.startsWith("has")) return n.substring("has".length());
31 if (n.startsWith("uses")) return n.substring("uses".length());
32
33 return n;
34 }
35 }
36
37 private Attribute currObj;
38 private MethodWrapper[] methodWrappers;
39 private int position;
40 private Node node;
41
42 private static Map<Class, MethodWrapper[]> methodCache = new HashMap<Class, MethodWrapper[]>();
43
44 public AttributeAxisIterator(Node contextNode) {
45 this.node = contextNode;
46 if (!methodCache.containsKey(contextNode.getClass())) {
47 Method[] preFilter = contextNode.getClass().getMethods();
48 List<MethodWrapper> postFilter = new ArrayList<MethodWrapper>();
49 for (int i = 0; i < preFilter.length; i++) {
50 if (isAttributeAccessor(preFilter[i])) {
51 postFilter.add(new MethodWrapper(preFilter[i]));
52 }
53 }
54 methodCache.put(contextNode.getClass(), postFilter.toArray(new MethodWrapper[postFilter.size()]));
55 }
56 this.methodWrappers = methodCache.get(contextNode.getClass());
57
58 this.position = 0;
59 this.currObj = getNextAttribute();
60 }
61
62 public Attribute next() {
63 if (currObj == null) {
64 throw new IndexOutOfBoundsException();
65 }
66 Attribute ret = currObj;
67 currObj = getNextAttribute();
68 return ret;
69 }
70
71 public boolean hasNext() {
72 return currObj != null;
73 }
74
75 public void remove() {
76 throw new UnsupportedOperationException();
77 }
78
79 private Attribute getNextAttribute() {
80 if (position == methodWrappers.length) {
81 return null;
82 }
83 MethodWrapper m = methodWrappers[position++];
84 return new Attribute(node, m.name, m.method);
85 }
86
87 protected boolean isAttributeAccessor(Method method) {
88
89 String methodName = method.getName();
90
91 return (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType() || String.class == method.getReturnType())
92 && (method.getParameterTypes().length == 0)
93 && (Void.TYPE != method.getReturnType())
94 && !methodName.startsWith("jjt")
95 && !methodName.equals("toString")
96 && !methodName.equals("getScope")
97 && !methodName.equals("getClass")
98 && !methodName.equals("getTypeNameNode")
99 && !methodName.equals("getImportedNameNode")
100 && !methodName.equals("hashCode");
101 }
102 }