Search in sources :

Example 1 with ExpressionException

use of org.opennms.netmgt.measurements.api.exceptions.ExpressionException in project opennms by OpenNMS.

the class JEXLExpressionEngine method applyExpressions.

/**
 * {@inheritDoc}
 */
@Override
public void applyExpressions(final QueryRequest request, final FetchResults results) throws ExpressionException {
    Preconditions.checkNotNull(request, "request argument");
    Preconditions.checkNotNull(results, "results argument");
    final int numExpressions = request.getExpressions().size();
    // Don't do anything if there are no expressions
    if (numExpressions < 1) {
        return;
    }
    // Use to keep track of transient expression so that we don't
    // allocate memory to store their results
    int numNonTransientExpression = 0;
    boolean[] transientFlags = new boolean[numExpressions];
    // Compile the expressions
    int j, k = 0;
    final LinkedHashMap<String, org.apache.commons.jexl2.Expression> expressions = Maps.newLinkedHashMap();
    for (final Expression e : request.getExpressions()) {
        // Populate the transientFlags array
        transientFlags[k] = e.getTransient();
        if (!transientFlags[k]) {
            numNonTransientExpression++;
        }
        k++;
        try {
            expressions.put(e.getLabel(), jexl.createExpression(e.getExpression()));
        } catch (JexlException ex) {
            throw new ExpressionException(ex, "Failed to parse expression label '{}'.", e.getLabel());
        }
    }
    // Prepare the JEXL context
    final Map<String, Object> jexlValues = Maps.newHashMap();
    final JexlContext context = new MapContext(jexlValues);
    // Add constants (i.e. values from strings.properties) retrieved by the fetch operation
    jexlValues.putAll(results.getConstants());
    LOG.debug("JEXL context constants: {}", jexlValues);
    // Add some additional constants for ease of use
    jexlValues.put("__inf", Double.POSITIVE_INFINITY);
    jexlValues.put("__neg_inf", Double.NEGATIVE_INFINITY);
    jexlValues.put("NaN", Double.NaN);
    jexlValues.put("__E", java.lang.Math.E);
    jexlValues.put("__PI", java.lang.Math.PI);
    // Add JexlEvaluateFunctions with current context and jexl engine to allow string constants to be evaluated.
    JexlEvaluateFunctions jexlEvaluateFunctions = new JexlEvaluateFunctions(context, jexl);
    jexl.getFunctions().put("jexl", jexlEvaluateFunctions);
    final long[] timestamps = results.getTimestamps();
    final Map<String, double[]> columns = results.getColumns();
    final int numRows = timestamps.length;
    // Calculate the time span
    jexlValues.put("__diff_time", numRows < 1 ? 0d : timestamps[numRows - 1] - timestamps[0]);
    final double[][] expressionValues = new double[numNonTransientExpression][numRows];
    // Iterate through all of the rows, apply the expressions
    for (int i = 0; i < numRows; i++) {
        // Evaluate every expression, in the same order as which they appeared in the query
        j = k = 0;
        for (final Map.Entry<String, org.apache.commons.jexl2.Expression> expressionEntry : expressions.entrySet()) {
            // Update the timestamp
            jexlValues.put("timestamp", timestamps[i]);
            // add index as a referenced variable in context
            jexlValues.put("__i", Integer.valueOf(i));
            // overwriting values from the last loop
            for (final String sourceLabel : columns.keySet()) {
                jexlValues.put(sourceLabel, columns.get(sourceLabel)[i]);
                // add reference to complete array for each column to allow backwards referencing of samples
                jexlValues.put("__" + sourceLabel, columns.get(sourceLabel));
            }
            // Evaluate the expression
            try {
                Object derived = expressionEntry.getValue().evaluate(context);
                double derivedAsDouble = Utils.toDouble(derived);
                // Only store the values for non-transient expressions
                if (!transientFlags[j++]) {
                    expressionValues[k++][i] = derivedAsDouble;
                }
                // Store the result back in the context, so that it can be referenced
                // by subsequent expression in the row
                jexlValues.put(expressionEntry.getKey(), derivedAsDouble);
            } catch (NullPointerException | NumberFormatException e) {
                throw new ExpressionException(e, "The return value from expression with label '" + expressionEntry.getKey() + "' could not be cast to a Double.");
            } catch (JexlException e) {
                throw new ExpressionException(e, "Failed to evaluate expression with label '" + expressionEntry.getKey() + "'.");
            }
        }
    }
    // Store the results
    j = k = 0;
    for (final String expressionLabel : expressions.keySet()) {
        if (!transientFlags[j++]) {
            columns.put(expressionLabel, expressionValues[k++]);
        }
    }
}
Also used : JexlException(org.apache.commons.jexl2.JexlException) MapContext(org.apache.commons.jexl2.MapContext) ExpressionException(org.opennms.netmgt.measurements.api.exceptions.ExpressionException) Expression(org.opennms.netmgt.measurements.model.Expression) JexlContext(org.apache.commons.jexl2.JexlContext) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 2 with ExpressionException

use of org.opennms.netmgt.measurements.api.exceptions.ExpressionException in project opennms by OpenNMS.

the class MeasurementsRestService method query.

/**
 * Retrieves the measurements of many resources and performs
 * arbitrary calculations on these.
 *
 * This a read-only query, however we use a POST instead of GET
 * since the request parameters are difficult to express in a query string.
 */
@POST
@Path("/")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_ATOM_XML })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_ATOM_XML })
@Transactional(readOnly = true)
public QueryResponse query(final QueryRequest request) {
    Preconditions.checkState(service != null);
    LOG.debug("Executing query with {}", request);
    QueryResponse response = null;
    try {
        response = service.query(request);
    } catch (ExpressionException e) {
        throw getException(Status.BAD_REQUEST, e, "An error occurred while evaluating an expression: {}", e.getMessage());
    } catch (FilterException | ValidationException e) {
        throw getException(Status.BAD_REQUEST, e, e.getMessage());
    } catch (ResourceNotFoundException e) {
        throw getException(Status.NOT_FOUND, e, e.getMessage());
    } catch (FetchException e) {
        throw getException(Status.INTERNAL_SERVER_ERROR, e, e.getMessage());
    } catch (Exception e) {
        throw getException(Status.INTERNAL_SERVER_ERROR, e, "Query failed: {}", e.getMessage());
    }
    // Return a 204 if there are no columns
    if (response.getColumns().length == 0) {
        throw getException(Status.NO_CONTENT, "No content.");
    }
    return response;
}
Also used : ValidationException(org.opennms.netmgt.measurements.api.exceptions.ValidationException) QueryResponse(org.opennms.netmgt.measurements.model.QueryResponse) FilterException(org.opennms.netmgt.measurements.api.exceptions.FilterException) FetchException(org.opennms.netmgt.measurements.api.exceptions.FetchException) ResourceNotFoundException(org.opennms.netmgt.measurements.api.exceptions.ResourceNotFoundException) ExpressionException(org.opennms.netmgt.measurements.api.exceptions.ExpressionException) FetchException(org.opennms.netmgt.measurements.api.exceptions.FetchException) FilterException(org.opennms.netmgt.measurements.api.exceptions.FilterException) ResourceNotFoundException(org.opennms.netmgt.measurements.api.exceptions.ResourceNotFoundException) ValidationException(org.opennms.netmgt.measurements.api.exceptions.ValidationException) WebApplicationException(javax.ws.rs.WebApplicationException) ExpressionException(org.opennms.netmgt.measurements.api.exceptions.ExpressionException) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) Transactional(org.springframework.transaction.annotation.Transactional)

Aggregations

ExpressionException (org.opennms.netmgt.measurements.api.exceptions.ExpressionException)2 LinkedHashMap (java.util.LinkedHashMap)1 Map (java.util.Map)1 Consumes (javax.ws.rs.Consumes)1 POST (javax.ws.rs.POST)1 Path (javax.ws.rs.Path)1 Produces (javax.ws.rs.Produces)1 WebApplicationException (javax.ws.rs.WebApplicationException)1 JexlContext (org.apache.commons.jexl2.JexlContext)1 JexlException (org.apache.commons.jexl2.JexlException)1 MapContext (org.apache.commons.jexl2.MapContext)1 FetchException (org.opennms.netmgt.measurements.api.exceptions.FetchException)1 FilterException (org.opennms.netmgt.measurements.api.exceptions.FilterException)1 ResourceNotFoundException (org.opennms.netmgt.measurements.api.exceptions.ResourceNotFoundException)1 ValidationException (org.opennms.netmgt.measurements.api.exceptions.ValidationException)1 Expression (org.opennms.netmgt.measurements.model.Expression)1 QueryResponse (org.opennms.netmgt.measurements.model.QueryResponse)1 Transactional (org.springframework.transaction.annotation.Transactional)1