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.InvocationTargetException;
9   import java.lang.reflect.Method;
10  import java.util.Iterator;
11  import java.util.Map;
12  import java.util.HashMap;
13  import java.util.List;
14  import java.util.ArrayList;
15  import java.util.LinkedList;
16  
17  // before any optimization, this took 22.9 seconds:
18  // time ./pmd.sh /usr/local/java/src/java/lang text basic > rpt.txt
19  // after caching and preprocessing, takes about 21.0 seconds
20  public class AttributeAxisIterator implements Iterator {
21  
22      private static class MethodWrapper {
23          public Method method;
24          public String name;
25          public MethodWrapper(Method m) {
26              this.method = m;
27              this.name = truncateMethodName(m.getName());
28          }
29          private String truncateMethodName(String n) {
30              // about 70% of the methods start with 'get', so this case goes first
31              if (n.startsWith("get")) {
32                  n = n.substring("get".length());
33              } else if (n.startsWith("is")) {
34                  n = n.substring("is".length());
35              } else if (n.startsWith("has")) {
36                  n = n.substring("has".length());
37              } else if (n.startsWith("uses")) {
38                  n = n.substring("uses".length());
39              }
40              return n;
41          }
42      }
43  
44      private Object currObj;
45      private MethodWrapper[] methodWrappers;
46      private int position;
47      private Node node;
48  
49      private static Map methodCache = new HashMap();
50  
51      public AttributeAxisIterator(Node contextNode) {
52          this.node = contextNode;
53          if (!methodCache.containsKey(contextNode.getClass())) {
54              Method[] preFilter = contextNode.getClass().getMethods();
55              List postFilter = new ArrayList();
56              for (int i = 0; i<preFilter.length; i++) {
57                  if (isAttribute(preFilter[i])) {
58                      postFilter.add(new MethodWrapper(preFilter[i]));
59                  }
60              }
61              methodCache.put(contextNode.getClass(), (MethodWrapper[])postFilter.toArray(new MethodWrapper[postFilter.size()]));
62          }
63          this.methodWrappers = (MethodWrapper[])methodCache.get(contextNode.getClass());
64  
65          this.position = 0;
66          this.currObj = getNextAttribute();
67      }
68  
69      public Object next() {
70          if (currObj == null) {
71              throw new IndexOutOfBoundsException();
72          }
73          Object ret = currObj;
74          currObj = getNextAttribute();
75          return ret;
76      }
77  
78      public boolean hasNext() {
79          return currObj != null;
80      }
81  
82      public void remove() {
83          throw new UnsupportedOperationException();
84      }
85  
86      private Attribute getNextAttribute() {
87          if (position == methodWrappers.length) {
88              return null;
89          }
90          MethodWrapper m = methodWrappers[position];
91          position++;
92          return new Attribute(node, m.name, m.method);
93      }
94  
95      protected boolean isAttribute(Method method) {
96          return (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType() || String.class == method.getReturnType())
97          && (method.getParameterTypes().length == 0)
98                  && (Void.TYPE != method.getReturnType())
99                  && !method.getName().startsWith("jjt")
100                 && !method.getName().equals("toString")
101                 && !method.getName().equals("getScope")
102                 && !method.getName().equals("getClass")
103                 && !method.getName().equals("getTypeNameNode")
104                 && !method.getName().equals("getImportedNameNode")
105                 && !method.getName().equals("hashCode");
106     }
107 }