package org.apache.lucene.queryparser.flexible.aqp.processors;
import java.util.List;
import java.util.Set;
import org.antlr.runtime.CharStream;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.standard.parser.ParseException;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler;
import org.apache.lucene.queryparser.flexible.core.messages.QueryParserMessages;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessor;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl;
import org.apache.lucene.queryparser.flexible.aqp.config.AqpFeedback;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpANTLRNode;
import org.apache.lucene.queryparser.flexible.aqp.parser.AqpStandardQueryConfigHandler;
/**
* A generic class that is used by other query processors, eg.
* {@link AqpQNORMALProcessor}
*
*
*
*/
public class AqpQProcessor extends QueryNodeProcessorImpl implements
QueryNodeProcessor {
public String defaultField = null;
@Override
protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException {
if (node instanceof AqpANTLRNode) {
AqpANTLRNode n = (AqpANTLRNode) node;
if (nodeIsWanted(n)) {
return createQNode(n);
}
}
return node;
}
@Override
protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException {
return node;
}
@Override
protected List<QueryNode> setChildrenOrder(List<QueryNode> children)
throws QueryNodeException {
return children;
}
public boolean nodeIsWanted(AqpANTLRNode node) {
throw new UnsupportedOperationException();
}
public QueryNode createQNode(AqpANTLRNode node) throws QueryNodeException {
throw new UnsupportedOperationException();
}
public String getDefaultFieldName() throws QueryNodeException {
QueryConfigHandler queryConfig = getQueryConfigHandler();
String defaultField = null;
if (queryConfig != null) {
if (queryConfig
.has(AqpStandardQueryConfigHandler.ConfigurationKeys.DEFAULT_FIELD)) {
defaultField = queryConfig
.get(AqpStandardQueryConfigHandler.ConfigurationKeys.DEFAULT_FIELD);
}
}
return defaultField;
}
public AqpFeedback getFeedbackAttr() throws QueryNodeException {
QueryConfigHandler config = getQueryConfigHandler();
if (config.has(AqpStandardQueryConfigHandler.ConfigurationKeys.FEEDBACK)) {
return config
.get(AqpStandardQueryConfigHandler.ConfigurationKeys.FEEDBACK);
} else {
throw new QueryNodeException(new MessageImpl(
QueryParserMessages.NODE_ACTION_NOT_SUPPORTED,
"Configuration error, missing AqpFeedback.class in the config!"));
}
}
public static QueryNode getTerminalNode(QueryNode node) {
while (!node.isLeaf()) {
return getTerminalNode(node.getChildren().get(
node.getChildren().size() - 1));
}
return node;
}
public static OriginalInput getOriginalInput(AqpANTLRNode node, Set<String> labelsToIncreaseCount)
throws ParseException {
CharStream inputStream = getInputStream(node);
if (inputStream == null) {
throw new ParseException(new MessageImpl(
"The supplied tree doesn't have input stream"));
}
int[] startIndex = new int[] { inputStream.size() };
getTheLowestIndex(startIndex, node);
if (startIndex[0] == -1) {
throw new ParseException(new MessageImpl(
"We cannot find where the input starts"));
}
int[] lastIndex = new int[] { startIndex[0] };
getTheHighestIndex(lastIndex, node, labelsToIncreaseCount);
if (lastIndex[0] < startIndex[0]) {
throw new ParseException(new MessageImpl(
"We cannot find where the input ends"));
}
return new OriginalInput(
inputStream.substring(startIndex[0], lastIndex[0]), startIndex[0],
lastIndex[0]);
}
public static CharStream getInputStream(QueryNode node) {
if (node.isLeaf()) {
if (node instanceof AqpANTLRNode) {
if (((AqpANTLRNode) node).getTree().getToken().getInputStream() != null) {
return ((AqpANTLRNode) node).getTree().getToken().getInputStream();
}
}
} else {
for (QueryNode child : node.getChildren()) {
CharStream r = getInputStream(child);
if (r != null) {
return r;
}
}
}
return null;
}
private static void getTheHighestIndex(int[] i, QueryNode node, Set<String> labelsToIncreaseCount) {
if (!node.isLeaf()) {
for (QueryNode n : node.getChildren()) {
getTheHighestIndex(i, n, labelsToIncreaseCount);
}
}
if (node instanceof AqpANTLRNode) {
int si = ((AqpANTLRNode) node).getInputTokenEnd();
/*
* In the grammar, we are generating AST tree, but leaving out
* brackets, because they were not deemed interesting to see -
* but this means we don't know their position, so if the node
* contained the QRANGE or something similar, we'll see the
* input shortened by n x 1
*/
if (labelsToIncreaseCount != null) {
String label = ((AqpANTLRNode) node).getTokenLabel();
if (labelsToIncreaseCount.contains(label))
i[0] = i[0]+1;
}
if (i[0] < si) {
i[0] = si;
}
}
}
private static void getTheLowestIndex(int[] i, QueryNode node) {
if (node instanceof AqpANTLRNode) {
int si = ((AqpANTLRNode) node).getInputTokenStart();
if (si > -1 && si < i[0]) {
i[0] = si;
}
}
if (!node.isLeaf()) {
for (QueryNode n : node.getChildren()) {
getTheLowestIndex(i, n);
}
}
}
public static class OriginalInput {
public String value;
public int start;
public int end;
public OriginalInput(String value, int startIndex, int endIndex) {
this.value = value;
this.start = startIndex;
this.end = endIndex;
}
public String toString() {
return String.format("%s <%d:%d>", this.value, this.start, this.end);
}
}
}