FutureParserContextImpl.java
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.esigate.parser.future;
import java.io.IOException;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.Future;
import org.apache.http.HttpResponse;
import org.esigate.HttpErrorPage;
import org.esigate.impl.DriverRequest;
/**
*
* The stack of tags corresponding to the current position in the document
* <p>
* This class is based on ParserContextImpl
*
* @see org.esigate.parser.ParserContextImpl
*
*
* @author Nicolas Richeton
*
*/
class FutureParserContextImpl implements FutureParserContext {
private final RootAdapter root;
private final DriverRequest httpRequest;
private final HttpResponse httpResponse;
private final Stack<Pair> stack = new Stack<>();
private Map<String, Object> data;
FutureParserContextImpl(FutureAppendable root, DriverRequest httpRequest, HttpResponse httpResponse,
Map<String, Object> data) {
this.root = new RootAdapter(root);
this.httpRequest = httpRequest;
this.httpResponse = httpResponse;
this.data = data;
}
@Override
public <T> T findAncestor(Class<T> type) {
T result = null;
for (int i = stack.size() - 1; i > -1; i--) {
FutureElement currentElement = stack.elementAt(i).element;
if (type.isInstance(currentElement)) {
result = type.cast(currentElement);
break;
}
}
// try with root
if (result == null && type.isInstance(root.root)) {
result = type.cast(root.root);
}
return result;
}
/** {@inheritDoc} */
@Override
public boolean reportError(FutureElement el, Exception e) {
boolean result = false;
FutureElement current = el.getParent();
while (current != null) {
if (current.onError(e, this)) {
result = true;
break;
}
current = current.getParent();
}
return result;
}
void startElement(FutureElementType type, FutureElement element, String tag) throws IOException, HttpErrorPage {
element.onTagStart(tag, this);
stack.push(new Pair(type, element));
}
void endElement(String tag) throws IOException, HttpErrorPage {
FutureElement element = stack.pop().element;
element.onTagEnd(tag, this);
}
boolean isCurrentTagEnd(String tag) {
return !stack.isEmpty() && stack.peek().type.isEndTag(tag);
}
/** Writes characters into current writer. */
public void characters(Future<CharSequence> csq) throws IOException {
getCurrent().characters(csq);
}
@Override
public FutureElement getCurrent() {
FutureElement result = root;
if (!stack.isEmpty()) {
result = stack.peek().element;
}
return result;
}
@Override
public DriverRequest getHttpRequest() {
return this.httpRequest;
}
private static class Pair {
private final FutureElementType type;
private final FutureElement element;
public Pair(FutureElementType type2, FutureElement element) {
this.type = type2;
this.element = element;
}
}
private static class RootAdapter implements FutureElement {
private final FutureAppendable root;
public RootAdapter(FutureAppendable root) {
this.root = root;
}
@Override
public boolean onTagStart(String tag, FutureParserContext ctx) {
// Nothing to do, this is the root tag
return true;
}
@Override
public void onTagEnd(String tag, FutureParserContext ctx) {
// Nothing to do, this is the root tag
}
@Override
public boolean onError(Exception e, FutureParserContext ctx) {
return false;
}
@Override
public void characters(Future<CharSequence> csq) throws IOException {
this.root.enqueueAppend(csq);
}
/*
* (non-Javadoc)
*
* @see org.esigate.parser.future.FutureElement#getParent()
*/
@Override
public FutureElement getParent() {
// Root parser has no parent.
return null;
}
}
@Override
public HttpResponse getHttpResponse() {
return this.httpResponse;
}
@Override
public Object getData(String key) {
Object result = null;
if (this.data != null) {
result = this.data.get(key);
}
return result;
}
}