package org.apache.lucene.queryparser.flexible.aqp.processors;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler;
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.AndQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.OrQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpANTLRNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpAndQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpDefopQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpNearQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpNotQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpOrQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.parser.AqpStandardQueryConfigHandler;
/**
* This processor operates on OPERATOR nodes, these are the nodes with labels
* AND, OR, NOT, DEFOP, NEAR and possibly others.
*
* <p>
*
* I have decided to create special QueryNodes for each type of the operator,
* because the default implementation ({@link AndQueryNode}, {@link OrQueryNode}
* ) was confusing.
*
* <pre>
* AND
* - creates {@link AqpAndQueryNode}
* OR
* - creates {@link AqpOrQueryNode}
* NOT
* - creates {@link AqpNotQueryNode}
* NEAR
* - creates {@link AqpNearQueryNode}
* WITH
* - not implemented yet
* PARAGRAPH
* - not implemented yet
* </pre>
*
* This processor should run after {@link AqpDEFOPProcessor}, and also after
* {@link AqpMODIFIERProcessor} because modifiers should have precedence over
* operators. Like in the query: "this OR +that"
*
*/
public class AqpOPERATORProcessor extends AqpQProcessorPost {
@Override
public boolean nodeIsWanted(AqpANTLRNode node) {
if (node.getTokenName().equals("OPERATOR")) {
return true;
}
return false;
}
@Override
public QueryNode createQNode(AqpANTLRNode node) throws QueryNodeException {
String label = node.getTokenLabel();
if (label.equals("DEFOP")) {
return new AqpDefopQueryNode(node.getChildren(), getDefaultOperator());
} else if (label.equals("AND")) {
return new AqpAndQueryNode(node.getChildren());
} else if (label.equals("OR")) {
return new AqpOrQueryNode(node.getChildren());
} else if (label.equals("NOT")) {
return new AqpNotQueryNode(node.getChildren());
} else if (label.toUpperCase().contains("NEAR")) {
if (label.length() <= 4) {
return new AqpNearQueryNode(node.getChildren(),
getDefaultProximityValue());
} else {
int distance = Integer.parseInt(label.substring(4));
if (isProximityValueAllowed(distance)) {
return new AqpNearQueryNode(node.getChildren(), distance);
} else {
throw new QueryNodeException(new MessageImpl(
QueryParserMessages.INVALID_SYNTAX,
"Proximity is only allowed in a range: " + getRange()[0] + "-" + getRange()[1]));
}
}
} else {
throw new QueryNodeException(new MessageImpl(
QueryParserMessages.INVALID_SYNTAX, "Unknown operator " + label));
}
}
private Integer getDefaultProximityValue() throws QueryNodeException {
QueryConfigHandler queryConfig = getQueryConfigHandler();
if (queryConfig == null
|| !queryConfig
.has(AqpStandardQueryConfigHandler.ConfigurationKeys.DEFAULT_PROXIMITY)) {
throw new QueryNodeException(new MessageImpl(
QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR,
"Configuration error: " + "DefaultProximity value is missing"));
}
return queryConfig
.get(AqpStandardQueryConfigHandler.ConfigurationKeys.DEFAULT_PROXIMITY);
}
private int[] getRange() {
QueryConfigHandler queryConfig = getQueryConfigHandler();
return queryConfig
.get(AqpStandardQueryConfigHandler.ConfigurationKeys.ALLOWED_PROXIMITY_RANGE);
}
private boolean isProximityValueAllowed(int userValue) {
int[] range = getRange();
if (userValue >= range[0] && userValue <= range[1]) {
return true;
}
return false;
}
protected StandardQueryConfigHandler.Operator getDefaultOperator()
throws QueryNodeException {
QueryConfigHandler queryConfig = getQueryConfigHandler();
if (queryConfig != null) {
if (queryConfig
.has(StandardQueryConfigHandler.ConfigurationKeys.DEFAULT_OPERATOR)) {
return queryConfig
.get(StandardQueryConfigHandler.ConfigurationKeys.DEFAULT_OPERATOR);
}
}
throw new QueryNodeException(new MessageImpl(
QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR,
"Configuration error: "
+ StandardQueryConfigHandler.ConfigurationKeys.class.toString()
+ " is missing"));
}
}