View Javadoc

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 {
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              // about 70% of the methods start with 'get', so this case goes first
28              if (n.startsWith("get")) {
29                  n = n.substring("get".length());
30              } else if (n.startsWith("is")) {
31                  n = n.substring("is".length());
32              } else if (n.startsWith("has")) {
33                  n = n.substring("has".length());
34              } else if (n.startsWith("uses")) {
35                  n = n.substring("uses".length());
36              }
37              return n;
38          }
39      }
40  
41      private Object currObj;
42      private MethodWrapper[] methodWrappers;
43      private int position;
44      private Node node;
45  
46      private static Map methodCache = new HashMap();
47  
48      public AttributeAxisIterator(Node contextNode) {
49          this.node = contextNode;
50          if (!methodCache.containsKey(contextNode.getClass())) {
51              Method[] preFilter = contextNode.getClass().getMethods();
52              List postFilter = new ArrayList();
53              for (int i = 0; i < preFilter.length; i++) {
54                  if (isAttribute(preFilter[i])) {
55                      postFilter.add(new MethodWrapper(preFilter[i]));
56                  }
57              }
58              methodCache.put(contextNode.getClass(), (MethodWrapper[]) postFilter.toArray(new MethodWrapper[postFilter.size()]));
59          }
60          this.methodWrappers = (MethodWrapper[]) methodCache.get(contextNode.getClass());
61  
62          this.position = 0;
63          this.currObj = getNextAttribute();
64      }
65  
66      public Object next() {
67          if (currObj == null) {
68              throw new IndexOutOfBoundsException();
69          }
70          Object ret = currObj;
71          currObj = getNextAttribute();
72          return ret;
73      }
74  
75      public boolean hasNext() {
76          return currObj != null;
77      }
78  
79      public void remove() {
80          throw new UnsupportedOperationException();
81      }
82  
83      private Attribute getNextAttribute() {
84          if (position == methodWrappers.length) {
85              return null;
86          }
87          MethodWrapper m = methodWrappers[position];
88          position++;
89          return new Attribute(node, m.name, m.method);
90      }
91  
92      protected boolean isAttribute(Method method) {
93          return (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType() || String.class == method.getReturnType())
94                  && (method.getParameterTypes().length == 0)
95                  && (Void.TYPE != method.getReturnType())
96                  && !method.getName().startsWith("jjt")
97                  && !method.getName().equals("toString")
98                  && !method.getName().equals("getScope")
99                  && !method.getName().equals("getClass")
100                 && !method.getName().equals("getTypeNameNode")
101                 && !method.getName().equals("getImportedNameNode")
102                 && !method.getName().equals("hashCode");
103     }
104 }