Java tutorial
/* * Copyright 2014-2015 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed 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.hawkular.metrics.core.impl; import static org.hawkular.metrics.core.api.DataPoint.TIMESTAMP_COMPARATOR; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.RandomAccess; import org.hawkular.metrics.core.api.BucketedOutput; import org.hawkular.metrics.core.api.Buckets; import org.hawkular.metrics.core.api.DataPoint; import org.hawkular.metrics.core.api.Metric; import org.hawkular.metrics.core.api.MetricId; import com.google.common.collect.Lists; import rx.functions.Func1; /** * Transform a {@link Metric} with its {@link org.hawkular.metrics.core.api.DataPoint} * into a {@link org.hawkular.metrics.core.api.BucketedOutput}. * * @param <DATA> type of metric data, like {@link org.hawkular.metrics.core.api.DataPoint<Double>} * @param <POINT> type of bucket points, like {@link org.hawkular.metrics.core.api.GaugeBucketDataPoint} * * @author Thomas Segismont */ public abstract class BucketedOutputMapper<DATA, POINT> implements Func1<List<DataPoint<DATA>>, BucketedOutput<POINT>> { protected final Buckets buckets; private String tenantId; private MetricId id; /** * Availability queries have been refactored to return data is ascending order, * but some gauge data queries return data in descending order. */ private boolean isDescending; /** * @param buckets the bucket configuration */ public BucketedOutputMapper(String tenantId, MetricId id, Buckets buckets) { this(tenantId, id, buckets, false); } public BucketedOutputMapper(String tenantId, MetricId id, Buckets buckets, boolean isDescending) { this.tenantId = tenantId; this.id = id; this.buckets = buckets; this.isDescending = isDescending; } @Override public BucketedOutput<POINT> call(List<DataPoint<DATA>> dataList) { BucketedOutput<POINT> output = new BucketedOutput<>(tenantId, id.getName(), Collections.emptyMap()); output.setData(new ArrayList<>(buckets.getCount())); if (!(dataList instanceof RandomAccess)) { dataList = new ArrayList<>(dataList); } if (isDescending) { dataList = Lists.reverse(dataList); // We expect input data to be sorted in descending order } int dataIndex = 0; DataPoint<DATA> previous; for (int bucketIndex = 0; bucketIndex < buckets.getCount(); bucketIndex++) { long from = buckets.getStart() + bucketIndex * buckets.getStep(); long to = buckets.getStart() + (bucketIndex + 1) * buckets.getStep(); if (dataIndex >= dataList.size()) { // Reached end of data points output.getData().add(newEmptyPointInstance(from, to)); continue; } DataPoint<DATA> current = dataList.get(dataIndex); if (current.getTimestamp() >= to) { // Current data point does not belong to this bucket output.getData().add(newEmptyPointInstance(from, to)); continue; } List<DataPoint<DATA>> metricDatas = new ArrayList<>(); do { // Add current value to this bucket's summary metricDatas.add(current); // Move to next data point previous = current; dataIndex++; current = dataIndex < dataList.size() ? dataList.get(dataIndex) : null; // checkOrder(previous, current); // Continue until end of data points is reached or data point does not belong to this bucket } while (current != null && current.getTimestamp() < to); output.getData().add(newPointInstance(from, to, metricDatas)); } return output; } private void checkOrder(DataPoint<DATA> previous, DataPoint<DATA> current) { if (previous != null && current != null && TIMESTAMP_COMPARATOR.compare(previous, current) > 0) { throw new IllegalArgumentException("Expected to iterate over data sorted by time ascending"); } } /** * Create an empty bucket data point instance. * * @param from start timestamp of the bucket * @param to end timestamp of the bucket * * @return an empty bucket data point */ protected abstract POINT newEmptyPointInstance(long from, long to); /** * Create a bucket data point from the metric data in this bucket. * * @param from start timestamp of the bucket * @param to end timestamp of the bucket * @param metricDatas metric data in this bucket, ordered by {@link DataPoint#TIMESTAMP_COMPARATOR} * * @return a bucket data point summurazing the metric data */ protected abstract POINT newPointInstance(long from, long to, List<DataPoint<DATA>> metricDatas); }