001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd.jaxen;
004:
005: import net.sourceforge.pmd.ast.Node;
006:
007: import java.lang.reflect.Method;
008: import java.util.ArrayList;
009: import java.util.HashMap;
010: import java.util.Iterator;
011: import java.util.List;
012: import java.util.Map;
013:
014: public class AttributeAxisIterator implements Iterator<Attribute> {
015:
016: private static class MethodWrapper {
017: public Method method;
018: public String name;
019:
020: public MethodWrapper(Method m) {
021: this .method = m;
022: this .name = truncateMethodName(m.getName());
023: }
024:
025: private String truncateMethodName(String n) {
026: // about 70% of the methods start with 'get', so this case goes first
027: if (n.startsWith("get"))
028: return n.substring("get".length());
029: if (n.startsWith("is"))
030: return n.substring("is".length());
031: if (n.startsWith("has"))
032: return n.substring("has".length());
033: if (n.startsWith("uses"))
034: return n.substring("uses".length());
035:
036: return n;
037: }
038: }
039:
040: private Attribute currObj;
041: private MethodWrapper[] methodWrappers;
042: private int position;
043: private Node node;
044:
045: private static Map<Class, MethodWrapper[]> methodCache = new HashMap<Class, MethodWrapper[]>();
046:
047: public AttributeAxisIterator(Node contextNode) {
048: this .node = contextNode;
049: if (!methodCache.containsKey(contextNode.getClass())) {
050: Method[] preFilter = contextNode.getClass().getMethods();
051: List<MethodWrapper> postFilter = new ArrayList<MethodWrapper>();
052: for (int i = 0; i < preFilter.length; i++) {
053: if (isAttributeAccessor(preFilter[i])) {
054: postFilter.add(new MethodWrapper(preFilter[i]));
055: }
056: }
057: methodCache.put(contextNode.getClass(), postFilter
058: .toArray(new MethodWrapper[postFilter.size()]));
059: }
060: this .methodWrappers = methodCache.get(contextNode.getClass());
061:
062: this .position = 0;
063: this .currObj = getNextAttribute();
064: }
065:
066: public Attribute next() {
067: if (currObj == null) {
068: throw new IndexOutOfBoundsException();
069: }
070: Attribute ret = currObj;
071: currObj = getNextAttribute();
072: return ret;
073: }
074:
075: public boolean hasNext() {
076: return currObj != null;
077: }
078:
079: public void remove() {
080: throw new UnsupportedOperationException();
081: }
082:
083: private Attribute getNextAttribute() {
084: if (position == methodWrappers.length) {
085: return null;
086: }
087: MethodWrapper m = methodWrappers[position++];
088: return new Attribute(node, m.name, m.method);
089: }
090:
091: protected boolean isAttributeAccessor(Method method) {
092:
093: String methodName = method.getName();
094:
095: return (Integer.TYPE == method.getReturnType()
096: || Boolean.TYPE == method.getReturnType() || String.class == method
097: .getReturnType())
098: && (method.getParameterTypes().length == 0)
099: && (Void.TYPE != method.getReturnType())
100: && !methodName.startsWith("jjt")
101: && !methodName.equals("toString")
102: && !methodName.equals("getScope")
103: && !methodName.equals("getClass")
104: && !methodName.equals("getTypeNameNode")
105: && !methodName.equals("getImportedNameNode")
106: && !methodName.equals("hashCode");
107: }
108: }
|