org.apache.metron.stellar.dsl.functions.OrdinalFunctions.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.metron.stellar.dsl.functions.OrdinalFunctions.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.metron.stellar.dsl.functions;

import com.google.common.collect.Iterables;
import org.apache.metron.stellar.common.utils.ConversionUtils;
import org.apache.metron.stellar.dsl.BaseStellarFunction;
import org.apache.metron.stellar.dsl.Stellar;
import java.util.List;
import java.util.function.BiFunction;
import static org.apache.metron.stellar.common.utils.ConversionUtils.convert;

public class OrdinalFunctions {

    /**
     * Stellar Function: MAX
     * <p>
     * Return the maximum value of a list of input values in a Stellar list
     */
    @Stellar(name = "MAX", description = "Returns the maximum value of a list of input values or from a statistics object", params = {
            "stats - The Stellar statistics object",
            "list - List of arguments. The list may only contain objects that are mutually comparable / ordinal (implement java.lang.Comparable interface)"
                    + " Multi type numeric comparisons are supported: MAX([10,15L,15.3]) would return 15.3, but MAX(['23',25]) will fail and return null as strings and numbers can't be compared." }, returns = "The maximum value in the list or from stats, or null if the list is empty or the input values were not comparable.")
    public static class Max extends BaseStellarFunction {

        @Override
        public Object apply(List<Object> args) {
            if (args.size() < 1 || args.get(0) == null) {
                throw new IllegalStateException("MAX function requires at least one argument");
            }
            Object firstArg = args.get(0);
            if (firstArg instanceof Ordinal) {
                Ordinal stats = convert(firstArg, Ordinal.class);
                return stats.getMax();
            } else if (firstArg instanceof Iterable) {
                Iterable<Comparable> list = (Iterable<Comparable>) args.get(0);
                return orderList(list, (ret, val) -> ret.compareTo(val) < 0, "MAX");
            } else {
                throw new IllegalStateException(
                        "MAX function expects either 'a StatisticsProvider object' or 'Stellar list of values'");
            }

        }
    }

    /**
     * Stellar Function: MIN
     * <p>
     * Return the minimum value of a list of input values in a Stellar list
     */
    @Stellar(name = "MIN", description = "Returns the minimum value of a list of input values", params = {
            "stats - The Stellar statistics object",
            "list - List of arguments. The list may only contain objects that are mutually comparable / ordinal (implement java.lang.Comparable interface)"
                    + " Multi type numeric comparisons are supported: MIN([10,15L,15.3]) would return 10, but MIN(['23',25]) will fail and return null as strings and numbers can't be compared." }, returns = "The minimum value in the list or from stats, or null if the list is empty or the input values were not comparable.")
    public static class Min extends BaseStellarFunction {
        @Override
        public Object apply(List<Object> args) {
            if (args.size() < 1 || args.get(0) == null) {
                throw new IllegalStateException("MIN function requires at least one argument");
            }
            Object firstArg = args.get(0);
            if (firstArg instanceof Ordinal) {
                Ordinal stats = convert(firstArg, Ordinal.class);
                return stats.getMin();
            } else if (firstArg instanceof Iterable) {
                Iterable<Comparable> list = (Iterable<Comparable>) args.get(0);
                return orderList(list, (ret, val) -> ret.compareTo(val) > 0, "MIN");
            } else {
                throw new IllegalStateException(
                        "MIN function expects either 'a StatisticsProvider object' or 'Stellar list of values' ");
            }
        }
    }

    private static Comparable orderList(Iterable<Comparable> list, BiFunction<Comparable, Comparable, Boolean> eval,
            String funcName) {
        if (Iterables.isEmpty(list)) {
            return null;
        }
        Object o = Iterables.getFirst(list, null);
        Comparable ret = null;
        for (Object valueVal : list) {
            if (valueVal == null) {
                continue;
            }
            Comparable value = null;
            if (!(valueVal instanceof Comparable)) {
                throw new IllegalStateException(
                        "Noncomparable object type " + valueVal.getClass().getName() + " submitted to " + funcName);
            } else {
                value = (Comparable) valueVal;
            }
            try {
                Comparable convertedRet = ConversionUtils.convert(ret, value.getClass());
                if (convertedRet == null && ret != null) {
                    throw new IllegalStateException("Incomparable objects were submitted to " + funcName + ": "
                            + ret.getClass() + " is incomparable to " + value.getClass());
                }
                if (ret == null || eval.apply(convertedRet, value)) {
                    ret = value;
                }
            } catch (ClassCastException cce) {
                throw new IllegalStateException(
                        "Incomparable objects were submitted to " + funcName + ": " + cce.getMessage(), cce);
            }
        }
        return ret;
    }

}