org.apache.metron.profiler.client.stellar.IntervalPredicate.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.metron.profiler.client.stellar.IntervalPredicate.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.profiler.client.stellar;

import org.apache.commons.lang3.Range;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * A predicate applied to a type T which can be converted into a long which indicates whether it exists
 * within a set of inclusive ranges of longs.  Generally these ranges may be thought of as timestamps.
 * In this interpretation, it will let you quickly indicate whether a given timestamp is within a set of timestamp
 * ranges.
 *
 * @param <T>
 */
public class IntervalPredicate<T> implements Predicate<T> {
    private final List<Range<Long>> intervals;
    private final Function<T, Long> timestampTransformer;

    /**
     * In the situation where we want longs directly.
     */
    public static final class Identity extends IntervalPredicate<Long> {

        public Identity(List<Range<Long>> intervals) {
            super(x -> x, intervals, Long.class);
        }
    }

    /**
     * Construct an interval predicate given a set of intervals and a function to convert T's to timestamps.
     * Please please please understand that intervals MUST be sorted.
     *
     * @param timestampTransformer The function to convert T's to timestamps.
     * @param intervals A sorted list of timestamp intervals.
     * @param clazz
     */
    public IntervalPredicate(Function<T, Long> timestampTransformer, List<Range<Long>> intervals, Class<T> clazz) {
        this.intervals = intervals;
        this.timestampTransformer = timestampTransformer;
    }

    private boolean containsInclusive(Range<Long> interval, long ts) {
        return interval.contains(ts) || interval.getMaximum() == ts;
    }

    /**
     * A helpful interval comparator that looks sorts the intervals according to left-side.
     */
    public static final Comparator<Range<Long>> INTERVAL_COMPARATOR = (o1, o2) -> {
        if (o1.getMinimum() == o2.getMinimum() && o1.getMaximum() == o2.getMaximum()) {
            return 0;
        } else {
            int ret = Long.compare(o1.getMinimum(), o2.getMinimum());
            if (ret == 0) {
                return Long.compare(o1.getMaximum(), o2.getMaximum());
            } else {
                return ret;
            }
        }
    };

    /**
     * Determine if x is in the set of intervals in O(log*n) time.
     * @param x
     * @return true if in the set of intervals and false otherwise.
     */
    @Override
    public boolean test(T x) {
        long ts = timestampTransformer.apply(x);
        int pos = Collections.binarySearch(intervals, Range.is(ts), INTERVAL_COMPARATOR);
        if (pos < 0) {
            pos = -pos - 1;
        }

        Optional<Range<Long>> right = pos >= 0 && pos < intervals.size() ? Optional.of(intervals.get(pos))
                : Optional.empty();
        Optional<Range<Long>> left = pos - 1 >= 0 && pos - 1 < intervals.size()
                ? Optional.of(intervals.get(pos - 1))
                : Optional.empty();
        return (right.isPresent() ? containsInclusive(right.get(), ts) : false)
                || (left.isPresent() ? containsInclusive(left.get(), ts) : false);
    }
}