use of datawave.webservice.query.exception.QueryException in project datawave by NationalSecurityAgency.
the class QueryModelVisitor method expandBinaryNodeFromModel.
/**
* Applies the forward mapping from the QueryModel to a node, expanding the node into an Or if needed.
*
* @param node
* @param data
* @return
*/
protected JexlNode expandBinaryNodeFromModel(JexlNode node, Object data) {
String field = JexlASTHelper.getIdentifier(node);
if (isFieldExcluded(field)) {
return node;
}
// Count the immediate children:
int childCount = node.jjtGetNumChildren();
if (childCount != 2) {
QueryException qe = new QueryException(DatawaveErrorCode.BINARY_NODE_TOO_MANY_CHILDREN, MessageFormat.format("Node: {0}", PrintingVisitor.formattedQueryString(node)));
throw new DatawaveFatalQueryException(qe);
}
// Find identifiers
List<ASTIdentifier> allidentifiers = JexlASTHelper.getIdentifiers(node);
// If we don't have any identifiers, we have nothing to expand
if (allidentifiers.isEmpty()) {
return node;
}
JexlNode leftNode = node.jjtGetChild(0);
JexlNode rightNode = node.jjtGetChild(1);
if (log.isTraceEnabled()) {
log.trace("leftNode:" + PrintingVisitor.formattedQueryString(leftNode));
log.trace("leftNodeQuery:" + JexlStringBuildingVisitor.buildQuery(leftNode));
log.trace("rightNode:" + PrintingVisitor.formattedQueryString(rightNode));
log.trace("rightNodeQuery:" + JexlStringBuildingVisitor.buildQuery(rightNode));
}
// this will expand identifiers that have a method connected to them
boolean leftState = JexlASTHelper.HasMethodVisitor.hasMethod(leftNode);
if (leftState) {
// there is a method under leftNode
leftNode = (JexlNode) leftNode.jjtAccept(this.simpleQueryModelVisitor, null);
}
boolean rightState = JexlASTHelper.HasMethodVisitor.hasMethod(rightNode);
if (rightState) {
// there is a method under rightNode
rightNode = (JexlNode) rightNode.jjtAccept(this.simpleQueryModelVisitor, null);
}
// expand any identifiers inside of methods/functions in the left and right nodes
leftNode = (JexlNode) leftNode.jjtAccept(this, null);
rightNode = (JexlNode) rightNode.jjtAccept(this, null);
if (log.isTraceEnabled()) {
log.trace("after expansion, leftNode:" + PrintingVisitor.formattedQueryString(leftNode));
log.trace("after expansion, leftNodeQuery:" + JexlStringBuildingVisitor.buildQuery(leftNode));
log.trace("after expansion, rightNode:" + PrintingVisitor.formattedQueryString(rightNode));
log.trace("after expansion, rightNodeQuery:" + JexlStringBuildingVisitor.buildQuery(rightNode));
}
// if state == true on either side, then there is a method on one side and we are done applying the model
if (leftState || rightState) {
JexlNode toReturn = JexlNodeFactory.buildUntypedBinaryNode(node, leftNode, rightNode);
if (log.isTraceEnabled()) {
log.trace("done early. returning:" + JexlStringBuildingVisitor.buildQuery(toReturn));
}
return toReturn;
}
JexlNode leftSeed, rightSeed;
Set<JexlNode> left = Sets.newHashSet(), right = Sets.newHashSet();
boolean isNullEquality = false;
if (node instanceof ASTEQNode && (leftNode instanceof ASTNullLiteral || rightNode instanceof ASTNullLiteral)) {
isNullEquality = true;
}
// the query has been previously groomed so that identifiers are on the left and literals are on the right
// an identifier with a method attached will have already been substituted above (and will return null for the IdentifierOpLiteral)
// The normal case of `IDENTIFIER op 'literal'`
JexlASTHelper.IdentifierOpLiteral op = JexlASTHelper.getIdentifierOpLiteral(node);
if (op != null) {
// One identifier
leftSeed = op.getIdentifier();
rightSeed = op.getLiteral();
if (rightSeed instanceof ASTNullLiteral && node instanceof ASTEQNode) {
isNullEquality = true;
}
} else {
// We know from above that childCount == 2. We may have a reference on both sides of the expression
leftSeed = node.jjtGetChild(0);
rightSeed = node.jjtGetChild(1);
}
if (leftSeed instanceof ASTReference) {
// String fieldName = JexlASTHelper.getIdentifier((JexlNode)leftSeed);
List<ASTIdentifier> identifiers = JexlASTHelper.getIdentifiers(leftSeed);
if (identifiers.size() > 1) {
log.warn("I did not expect to see more than one Identifier here for " + JexlStringBuildingVisitor.buildQuery(leftSeed) + " from " + JexlStringBuildingVisitor.buildQuery(leftNode));
}
for (ASTIdentifier identifier : identifiers) {
for (String fieldName : getAliasesForField(JexlASTHelper.deconstructIdentifier(identifier))) {
left.add(JexlNodeFactory.buildIdentifier(fieldName));
}
}
} else if (leftSeed instanceof ASTIdentifier) {
for (String fieldName : getAliasesForField(JexlASTHelper.deconstructIdentifier((ASTIdentifier) leftSeed))) {
left.add(JexlNodeFactory.buildIdentifier(fieldName));
}
} else {
// Not an identifier, therefore it's probably a literal
left.add(leftSeed);
}
if (rightSeed instanceof ASTReference) {
List<ASTIdentifier> identifiers = JexlASTHelper.getIdentifiers(rightSeed);
if (identifiers.size() > 1) {
log.warn("I did not expect to see more than one Identifier here for " + JexlStringBuildingVisitor.buildQuery(rightSeed) + " from " + JexlStringBuildingVisitor.buildQuery(rightNode));
}
for (ASTIdentifier identifier : identifiers) {
for (String fieldName : getAliasesForField(JexlASTHelper.deconstructIdentifier(identifier))) {
right.add(JexlNodeFactory.buildIdentifier(fieldName));
}
}
} else if (rightSeed instanceof ASTIdentifier) {
for (String fieldName : getAliasesForField(JexlASTHelper.deconstructIdentifier((ASTIdentifier) rightSeed))) {
right.add(JexlNodeFactory.buildIdentifier(fieldName));
}
} else {
// Not an identifier, therefore it's probably a literal
right.add(rightSeed);
}
boolean requiresAnd = isNullEquality || node instanceof ASTNENode;
@SuppressWarnings("unchecked") Set<List<JexlNode>> // retrieve the cartesian product
product = Sets.cartesianProduct(left, right);
/**
* use the product transformer to shallow copy the jexl nodes. We've created new nodes that will be embedded within an ast reference. As a result, we
* need to ensure that if we create a logical structure ( such as an or ) -- each literal references a unique identifier from the right. Otherwise,
* subsequent visitors will reference incorrection sub trees, and potentially negate the activity of the query model visitor
*/
Set<List<JexlNode>> newSet = product.stream().map(list -> list.stream().map(RebuildingVisitor::copy).collect(Collectors.toList())).collect(Collectors.toSet());
if (product.size() > 1) {
JexlNode expanded;
if (requiresAnd) {
expanded = JexlNodeFactory.createNodeTreeFromPairs(ContainerType.AND_NODE, node, newSet);
} else {
expanded = JexlNodeFactory.createNodeTreeFromPairs(ContainerType.OR_NODE, node, newSet);
}
if (log.isTraceEnabled())
log.trace("expanded:" + PrintingVisitor.formattedQueryString(expanded));
return expanded;
} else if (1 == product.size()) {
List<JexlNode> pair = product.iterator().next();
JexlNode expanded = JexlNodeFactory.buildUntypedBinaryNode(node, pair.get(0), pair.get(1));
if (log.isTraceEnabled())
log.trace("expanded:" + PrintingVisitor.formattedQueryString(expanded));
return expanded;
}
// If we couldn't map anything, return a copy
if (log.isTraceEnabled())
log.trace("just returning the original:" + PrintingVisitor.formattedQueryString(node));
return node;
}
use of datawave.webservice.query.exception.QueryException in project datawave by NationalSecurityAgency.
the class MetadataHelperQueryModelProvider method getQueryModel.
@Override
public QueryModel getQueryModel() {
QueryModel queryModel = null;
if (config.getQueryModel() != null) {
log.debug("Using a cached query model");
queryModel = config.getQueryModel();
} else if (null != config.getModelName() && null != config.getModelTableName()) {
log.debug("Generating a query model");
try {
queryModel = metadataHelper.getQueryModel(config.getModelTableName(), config.getModelName(), config.getUnevaluatedFields(), config.getDatatypeFilter());
config.setQueryModel(queryModel);
} catch (TableNotFoundException e) {
QueryException qe = new QueryException(DatawaveErrorCode.QUERY_MODEL_FETCH_ERROR, e);
log.error(qe);
throw new DatawaveFatalQueryException(qe);
}
if (log.isTraceEnabled()) {
log.trace("forward queryModel: " + queryModel.getForwardQueryMapping());
log.trace("reverse queryModel: " + queryModel.getReverseQueryMapping());
}
}
return queryModel;
}
use of datawave.webservice.query.exception.QueryException in project datawave by NationalSecurityAgency.
the class QueryExecutorBean method close.
private VoidResponse close(String id, Principal principal) {
VoidResponse response = new VoidResponse();
try {
boolean connectionRequestCanceled = accumuloConnectionRequestBean.cancelConnectionRequest(id, principal);
Pair<QueryLogic<?>, Connector> tuple = qlCache.pollIfOwnedBy(id, ((DatawavePrincipal) principal).getShortName());
if (tuple == null) {
try {
RunningQuery query = getQueryById(id, principal);
close(query);
} catch (Exception e) {
log.debug("Failed to close " + id + ", checking if closed previously");
// if this is a query that is in the closed query cache, then we have already successfully closed this query so ignore
if (!closedQueryCache.exists(id)) {
log.debug("Failed to close " + id + ", checking if connection request was canceled");
// if connection request was canceled, then the call was successful even if a RunningQuery was not found
if (!connectionRequestCanceled) {
log.error("Failed to close " + id, e);
throw e;
}
}
}
response.addMessage(id + " closed.");
} else {
QueryLogic<?> logic = tuple.getFirst();
try {
logic.close();
} catch (Exception e) {
log.error("Exception occurred while closing query logic; may be innocuous if scanners were running.", e);
}
connectionFactory.returnConnection(tuple.getSecond());
response.addMessage(id + " closed before create completed.");
}
// no longer need to remember this query
closedQueryCache.remove(id);
return response;
} catch (DatawaveWebApplicationException e) {
throw e;
} catch (Exception e) {
QueryException qe = new QueryException(DatawaveErrorCode.CLOSE_ERROR, e, MessageFormat.format("query_id: {0}", id));
log.error(qe, e);
response.addException(qe.getBottomQueryException());
int statusCode = qe.getBottomQueryException().getStatusCode();
throw new DatawaveWebApplicationException(qe, response, statusCode);
}
}
use of datawave.webservice.query.exception.QueryException in project datawave by NationalSecurityAgency.
the class QueryExecutorBean method next.
private BaseQueryResponse next(final String id, boolean checkForContentLookup) {
// in case we don't make it to creating the response from the QueryLogic
BaseQueryResponse response = responseObjectFactory.getEventQueryResponse();
Collection<String> proxyServers = null;
Principal p = ctx.getCallerPrincipal();
String userid = p.getName();
if (p instanceof DatawavePrincipal) {
DatawavePrincipal dp = (DatawavePrincipal) p;
userid = dp.getShortName();
proxyServers = dp.getProxyServers();
}
Span span = null;
RunningQuery query = null;
Query contentLookupSettings = null;
try {
ctx.getUserTransaction().begin();
// Not calling getQueryById() here. We don't want to pull the persisted definition.
query = queryCache.get(id);
// The lock should be released at the end of the method call.
if (!queryCache.lock(id)) {
throw new QueryException(DatawaveErrorCode.QUERY_LOCKED_ERROR);
}
// an error.
if (null == query || null == query.getConnection()) {
// status code.
if (null == query) {
List<Query> queries = persister.findById(id);
if (queries == null || queries.size() != 1) {
throw new NotFoundQueryException(DatawaveErrorCode.NO_QUERY_OBJECT_MATCH, MessageFormat.format("{0}", id));
}
}
throw new PreConditionFailedQueryException(DatawaveErrorCode.QUERY_TIMEOUT_OR_SERVER_ERROR, MessageFormat.format("id = {0}", id));
} else {
// Validate the query belongs to the caller
if (!query.getSettings().getOwner().equals(userid)) {
throw new UnauthorizedQueryException(DatawaveErrorCode.QUERY_OWNER_MISMATCH, MessageFormat.format("{0} != {1}", userid, query.getSettings().getOwner()));
}
// Set the active call and get next
query.setActiveCall(true);
response = _next(query, id, proxyServers, span);
// Conditionally swap the standard response with content
if (checkForContentLookup) {
final Query settings = query.getSettings();
final Parameter contentLookupParam = settings.findParameter(LookupUUIDUtil.PARAM_CONTENT_LOOKUP);
if ((null != contentLookupParam) && Boolean.parseBoolean(contentLookupParam.getParameterValue())) {
contentLookupSettings = settings;
}
}
// Unset the active call and return
query.setActiveCall(false);
}
} catch (NoResultsException e) {
if (query != null) {
query.setActiveCall(false);
if (query.getLogic().getCollectQueryMetrics()) {
try {
// do not set the error message here - zero results is not an error that should be added to metrics
metrics.updateMetric(query.getMetric());
} catch (Exception e1) {
log.error(e1.getMessage());
}
}
}
try {
ctx.getUserTransaction().setRollbackOnly();
} catch (Exception ex) {
log.error("Error marking transaction for roll back", ex);
}
// close the query, as there were no results and we are done here
close(id);
// remember that we auto-closed this query
closedQueryCache.add(id);
throw e;
} catch (DatawaveWebApplicationException e) {
if (query != null) {
query.setActiveCall(false);
if (query.getLogic().getCollectQueryMetrics()) {
query.getMetric().setError(e);
try {
metrics.updateMetric(query.getMetric());
} catch (Exception e1) {
log.error("Error updating query metrics", e1);
}
}
}
try {
ctx.getUserTransaction().setRollbackOnly();
} catch (Exception ex) {
log.error("Error marking transaction for roll back", ex);
}
if (e.getCause() instanceof NoResultsException) {
close(id);
// remember that we auto-closed this query
closedQueryCache.add(id);
}
throw e;
} catch (Exception e) {
log.error("Query Failed", e);
if (query != null) {
query.setActiveCall(false);
if (query.getLogic().getCollectQueryMetrics() == true) {
query.getMetric().setError(e);
try {
metrics.updateMetric(query.getMetric());
} catch (Exception e1) {
log.error("Error updating query metrics", e1);
}
}
}
try {
ctx.getUserTransaction().setRollbackOnly();
} catch (Exception ex) {
log.error("Error marking transaction for roll back", ex);
}
QueryException qe = new QueryException(DatawaveErrorCode.QUERY_NEXT_ERROR, e, MessageFormat.format("query id: {0}", id));
if (e.getCause() instanceof NoResultsException) {
log.debug("Got a nested NoResultsException", e);
close(id);
// remember that we auto-closed this query
closedQueryCache.add(id);
} else {
try {
close(id);
} catch (Exception ce) {
log.error(qe, ce);
}
log.error(qe, e);
response.addException(qe.getBottomQueryException());
}
int statusCode = qe.getBottomQueryException().getStatusCode();
throw new DatawaveWebApplicationException(qe, response, statusCode);
} finally {
queryCache.unlock(id);
try {
if (ctx.getUserTransaction().getStatus() == Status.STATUS_MARKED_ROLLBACK) {
ctx.getUserTransaction().rollback();
} else if (ctx.getUserTransaction().getStatus() != Status.STATUS_NO_TRANSACTION) {
// no reason to commit if transaction not started, ie Query not found exception
ctx.getUserTransaction().commit();
}
} catch (IllegalStateException e) {
log.error("Error committing transaction: thread not associated with transaction", e);
} catch (RollbackException e) {
log.error("Error committing transaction: marked for rollback due to error", e);
} catch (HeuristicMixedException e) {
log.error("Error committing transaction: partial commit of resources", e);
} catch (HeuristicRollbackException e) {
log.error("Error committing transaction: resources rolled back transaction", e);
} catch (Exception e) {
log.error("Error committing transaction: Unknown error", e);
} finally {
// Stop timing on this trace, if any
if (span != null) {
span.stop();
}
}
}
// If applicable, perform a paged content lookup (i.e., not streamed), replacing its results in the returned response
if (null != contentLookupSettings) {
final NextContentCriteria criteria = new NextContentCriteria(id, contentLookupSettings);
response = this.lookupUUIDUtil.lookupContentByNextResponse(criteria, response);
}
return response;
}
use of datawave.webservice.query.exception.QueryException in project datawave by NationalSecurityAgency.
the class QueryExecutorBean method listQueryLogic.
/**
* List QueryLogic types that are currently available
*
* @HTTP 200 Success
* @return datawave.webservice.result.QueryLogicResponse
* @RequestHeader X-ProxiedEntitiesChain use when proxying request for user, by specifying a chain of DNs of the identities to proxy
* @RequestHeader X-ProxiedIssuersChain required when using X-ProxiedEntitiesChain, specify one issuer DN per subject DN listed in X-ProxiedEntitiesChain
* @ResponseHeader X-OperationTimeInMS time spent on the server performing the operation, does not account for network or result serialization
*/
@Path("/listQueryLogic")
@Produces({ "application/xml", "text/xml", "application/json", "text/yaml", "text/x-yaml", "application/x-yaml", "text/html" })
@GET
@Interceptors({ ResponseInterceptor.class })
@Override
@Timed(name = "dw.query.listQueryLogic", absolute = true)
public QueryLogicResponse listQueryLogic() {
QueryLogicResponse response = new QueryLogicResponse();
List<QueryLogic<?>> logicList = queryLogicFactory.getQueryLogicList();
List<QueryLogicDescription> logicConfigurationList = new ArrayList<>();
// reference query necessary to avoid NPEs in getting the Transformer and BaseResponse
Query q = new QueryImpl();
Date now = new Date();
q.setExpirationDate(now);
q.setQuery("test");
q.setQueryAuthorizations("ALL");
for (QueryLogic<?> l : logicList) {
try {
QueryLogicDescription d = new QueryLogicDescription(l.getLogicName());
d.setAuditType(l.getAuditType(null).toString());
d.setLogicDescription(l.getLogicDescription());
Set<String> optionalQueryParameters = l.getOptionalQueryParameters();
if (optionalQueryParameters != null) {
d.setSupportedParams(new ArrayList<>(optionalQueryParameters));
}
Set<String> requiredQueryParameters = l.getRequiredQueryParameters();
if (requiredQueryParameters != null) {
d.setRequiredParams(new ArrayList<>(requiredQueryParameters));
}
Set<String> exampleQueries = l.getExampleQueries();
if (exampleQueries != null) {
d.setExampleQueries(new ArrayList<>(exampleQueries));
}
Set<String> requiredRoles = l.getRoleManager().getRequiredRoles();
if (requiredRoles != null) {
List<String> requiredRolesList = new ArrayList<>();
requiredRolesList.addAll(l.getRoleManager().getRequiredRoles());
d.setRequiredRoles(requiredRolesList);
}
try {
d.setResponseClass(l.getResponseClass(q));
} catch (QueryException e) {
log.error(e, e);
response.addException(e);
d.setResponseClass("unknown");
}
List<String> querySyntax = new ArrayList<>();
try {
Method m = l.getClass().getMethod("getQuerySyntaxParsers");
Object result = m.invoke(l);
if (result instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) result;
for (Object o : map.keySet()) querySyntax.add(o.toString());
}
} catch (Exception e) {
log.warn("Unable to get query syntax for query logic: " + l.getClass().getCanonicalName());
}
if (querySyntax.isEmpty()) {
querySyntax.add("CUSTOM");
}
d.setQuerySyntax(querySyntax);
logicConfigurationList.add(d);
} catch (Exception e) {
log.error("Error setting query logic description", e);
}
}
Collections.sort(logicConfigurationList, Comparator.comparing(QueryLogicDescription::getName));
response.setQueryLogicList(logicConfigurationList);
return response;
}
Aggregations