1
2
3
4 package net.sourceforge.pmd.lang.xml.ast;
5
6 import static net.sourceforge.pmd.lang.xml.ast.XmlNode.BEGIN_COLUMN;
7 import static net.sourceforge.pmd.lang.xml.ast.XmlNode.BEGIN_LINE;
8 import static net.sourceforge.pmd.lang.xml.ast.XmlNode.END_COLUMN;
9 import static net.sourceforge.pmd.lang.xml.ast.XmlNode.END_LINE;
10
11 import java.lang.reflect.InvocationHandler;
12 import java.lang.reflect.Method;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Iterator;
16 import java.util.List;
17
18 import net.sourceforge.pmd.lang.ast.xpath.Attribute;
19 import net.sourceforge.pmd.util.CompoundIterator;
20
21 import org.w3c.dom.Document;
22 import org.w3c.dom.NamedNodeMap;
23 import org.w3c.dom.Node;
24 import org.w3c.dom.NodeList;
25 import org.w3c.dom.Text;
26
27 public class XmlNodeInvocationHandler implements InvocationHandler {
28 private final Node node;
29 private Object userData;
30 private XmlParser parser;
31
32 public XmlNodeInvocationHandler(XmlParser parser, Node node) {
33 this.parser = parser;
34 this.node = node;
35 }
36
37 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
38
39 if (method.getDeclaringClass().isAssignableFrom(XmlNode.class)
40 && !"java.lang.Object".equals(method.getDeclaringClass().getName())) {
41 if ("jjtGetNumChildren".equals(method.getName())) {
42 return node.hasChildNodes() ? node.getChildNodes().getLength() : 0;
43 } else if ("jjtGetChild".equals(method.getName())) {
44 return parser.createProxy(node.getChildNodes().item(((Integer) args[0]).intValue()));
45 } else if ("jjtGetChildIndex".equals(method.getName())) {
46 Node parent = node.getParentNode();
47 NodeList childNodes = parent.getChildNodes();
48 for (int i = 0; i < childNodes.getLength(); i++) {
49 if (node == childNodes.item(i)) {
50 return i;
51 }
52 }
53 throw new IllegalStateException("This node is not a child of its parent: " + node);
54 } else if ("getImage".equals(method.getName())) {
55 if (node instanceof Text) {
56 return ((Text) node).getData();
57 } else {
58 return null;
59 }
60 } else if ("jjtGetParent".equals(method.getName())) {
61 Node parent = node.getParentNode();
62 if (parent != null && !(parent instanceof Document)) {
63 return parser.createProxy(parent);
64 } else {
65 return null;
66 }
67 } else if ("getAttributeIterator".equals(method.getName())) {
68 List<Iterator<Attribute>> iterators = new ArrayList<Iterator<Attribute>>();
69
70
71 final NamedNodeMap attributes = node.getAttributes();
72 iterators.add(new Iterator<Attribute>() {
73 private int index;
74
75 public boolean hasNext() {
76 return attributes != null && index < attributes.getLength();
77 }
78
79 public Attribute next() {
80 Node attributeNode = attributes.item(index++);
81 return new Attribute(parser.createProxy(node), attributeNode.getNodeName(), attributeNode
82 .getNodeValue());
83 }
84
85 public void remove() {
86 throw new UnsupportedOperationException();
87 }
88 });
89
90
91
92 if (proxy instanceof Text) {
93 iterators.add(Collections.singletonList(
94 new Attribute((net.sourceforge.pmd.lang.ast.Node) proxy, "Image", ((Text) proxy)
95 .getData())).iterator());
96 }
97
98
99
100
101
102
103 return new CompoundIterator<Attribute>(iterators.toArray(new Iterator[iterators.size()]));
104 } else if ("getBeginLine".equals(method.getName())) {
105 return getUserData(BEGIN_LINE);
106 } else if ("getBeginColumn".equals(method.getName())) {
107 return getUserData(BEGIN_COLUMN);
108 } else if ("getEndLine".equals(method.getName())) {
109 return getUserData(END_LINE);
110 } else if ("getEndColumn".equals(method.getName())) {
111 return getUserData(END_COLUMN);
112 } else if ("getNode".equals(method.getName())) {
113 return node;
114 } else if ("getUserData".equals(method.getName())) {
115 return userData;
116 } else if ("setUserData".equals(method.getName())) {
117 userData = args[0];
118 return null;
119 } else if ("isFindBoundary".equals(method.getName())) {
120 return false;
121 }
122 throw new UnsupportedOperationException("Method not supported for XmlNode: " + method);
123 }
124
125 else {
126 if ("toString".equals(method.getName())) {
127 String s = node.getNodeName();
128 s = s.replace("#", "");
129 return s;
130 }
131 Object result = method.invoke(node, args);
132 return result;
133 }
134 }
135
136 private Integer getUserData(String key) {
137 if (node.getUserData(key) != null) {
138 return (Integer) node.getUserData(key);
139 }
140 return Integer.valueOf(-1);
141 }
142 }