View Javadoc
1   /* 
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
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   * The stack of tags corresponding to the current position in the document
30   * <p>
31   * This class is based on ParserContextImpl
32   * 
33   * @see org.esigate.parser.ParserContextImpl
34   * 
35   * 
36   * @author Nicolas Richeton
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          // try with root
66          if (result == null && type.isInstance(root.root)) {
67              result = type.cast(root.root);
68          }
69  
70          return result;
71      }
72  
73      /** {@inheritDoc} */
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     /** Writes characters into current writer. */
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             // Nothing to do, this is the root tag
142             return true;
143         }
144 
145         @Override
146         public void onTagEnd(String tag, FutureParserContext ctx) {
147             // Nothing to do, this is the root tag
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          * (non-Javadoc)
162          * 
163          * @see org.esigate.parser.future.FutureElement#getParent()
164          */
165         @Override
166         public FutureElement getParent() {
167             // Root parser has no parent.
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 }