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