1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.esigate.parser;
17
18 import java.io.IOException;
19 import java.util.Stack;
20
21 import org.apache.http.HttpResponse;
22 import org.esigate.HttpErrorPage;
23 import org.esigate.impl.DriverRequest;
24
25
26
27
28
29
30
31
32 class ParserContextImpl implements ParserContext {
33 private final RootAdapter root;
34 private final DriverRequest httpRequest;
35 private final HttpResponse httpResponse;
36
37 private final Stack<ElementInfo> stack = new Stack<>();
38
39 ParserContextImpl(Appendable root, DriverRequest httpRequest, HttpResponse httpResponse) {
40 this.root = new RootAdapter(root);
41 this.httpRequest = httpRequest;
42 this.httpResponse = httpResponse;
43 }
44
45 @Override
46 public <T> T findAncestor(Class<T> type) {
47 T result = null;
48 for (int i = stack.size() - 1; i > -1; i--) {
49 Element currentElement = stack.elementAt(i).element;
50 if (type.isInstance(currentElement)) {
51 result = type.cast(currentElement);
52 break;
53 }
54 }
55
56 if (result == null && type.isInstance(root.root)) {
57 result = type.cast(root.root);
58 }
59
60 return result;
61 }
62
63
64 @Override
65 public boolean reportError(Exception e) {
66 boolean result = false;
67 for (int i = stack.size() - 1; i > -1; i--) {
68 Element element = stack.elementAt(i).element;
69 if (element.onError(e, this)) {
70 result = true;
71 break;
72 }
73 }
74 return result;
75 }
76
77 void startElement(ElementType type, Element element, String tag) throws IOException, HttpErrorPage {
78 boolean skipContent = false;
79 if (!stack.isEmpty()) {
80
81 skipContent = stack.peek().skipContent;
82 }
83 boolean elementDoesNotSkipContent = element.onTagStart(tag, this);
84 if (!skipContent) {
85 skipContent = !elementDoesNotSkipContent;
86 }
87 stack.push(new ElementInfo(type, element, skipContent));
88 }
89
90 void endElement(String tag) throws IOException, HttpErrorPage {
91 ElementInfo elementInfo = stack.pop();
92 if (!elementInfo.skipContent) {
93 elementInfo.element.onTagEnd(tag, this);
94 }
95 }
96
97 boolean isCurrentTagEnd(String tag) {
98 return !stack.isEmpty() && stack.peek().type.isEndTag(tag);
99 }
100
101
102 public void characters(CharSequence cs) throws IOException {
103 characters(cs, 0, cs.length());
104 }
105
106
107 void characters(CharSequence csq, int start, int end) throws IOException {
108 getCurrent().characters(csq, start, end);
109 }
110
111 @Override
112 public Element getCurrent() {
113 Element result = root;
114 if (!stack.isEmpty()) {
115 result = stack.peek().element;
116 }
117 return result;
118 }
119
120 @Override
121 public DriverRequest getHttpRequest() {
122 return this.httpRequest;
123 }
124
125 private static class ElementInfo {
126 private final ElementType type;
127 private final Element element;
128 private final boolean skipContent;
129
130 public ElementInfo(ElementType type, Element element, boolean skipContent) {
131 this.type = type;
132 this.element = element;
133 this.skipContent = skipContent;
134 }
135 }
136
137 private static class RootAdapter implements Element {
138 private final Appendable root;
139
140 public RootAdapter(Appendable root) {
141 this.root = root;
142 }
143
144 @Override
145 public boolean onTagStart(String tag, ParserContext ctx) {
146
147 return true;
148 }
149
150 @Override
151 public void onTagEnd(String tag, ParserContext ctx) {
152
153 }
154
155 @Override
156 public boolean onError(Exception e, ParserContext ctx) {
157 return false;
158 }
159
160 @Override
161 public void characters(CharSequence csq, int start, int end) throws IOException {
162 this.root.append(csq, start, end);
163 }
164
165 }
166
167 @Override
168 public HttpResponse getHttpResponse() {
169 return this.httpResponse;
170 }
171 }