// This file is part of OpenTSDB.
// Copyright (C) 2015 The OpenTSDB Authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2.1 of the License, or (at your
// option) any later version. This program is distributed in the hope that it
// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details. You should have received a copy
// of the GNU Lesser General Public License along with this program. If not,
// see <http://www.gnu.org/licenses/>.
package net.opentsdb.query.expression;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.hbase.async.Bytes.ByteMap;
import com.stumbleupon.async.Callback;
import com.stumbleupon.async.Deferred;
import net.opentsdb.core.DataPoint;
import net.opentsdb.core.DataPoints;
import net.opentsdb.core.MutableDataPoint;
import net.opentsdb.core.SeekableView;
import net.opentsdb.core.TSDB;
import net.opentsdb.core.Tags;
import net.opentsdb.meta.Annotation;
import net.opentsdb.uid.UniqueId.UniqueIdType;
import net.opentsdb.utils.ByteSet;
/**
* An ugly temporary class for converting from an expression datapoint to a
* standard data point for serialization in the default query format.
*/
public class EDPtoDPS implements DataPoints {
/** The TSDB used for UID to name lookups */
private final TSDB tsdb;
/** The index of this data point in the iterator */
private final int index;
/** The iterator that contains the results for this data point */
private final ExpressionIterator iterator;
/** The list of data points from the iterator from which we read */
private final ExpressionDataPoint[] edps;
/**
* Default ctor
* @param tsdb The TSDB used for UID to name lookups
* @param index The index of this data point in the iterator
* @param iterator The iterator that contains the results for this data point
*/
public EDPtoDPS(final TSDB tsdb, final int index,
final ExpressionIterator iterator) {
this.tsdb = tsdb;
this.index = index;
this.iterator = iterator;
edps = iterator.values();
}
@Override
public String metricName() {
try {
return metricNameAsync().joinUninterruptibly();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Should never be here", e);
}
}
@Override
public Deferred<String> metricNameAsync() {
if (edps[index].metricUIDs() == null) {
throw new IllegalStateException("Iterator UID was null for index " +
index + " and iterator " + iterator);
}
final byte[] uid = edps[index].metricUIDs().iterator().next();
return tsdb.getUidName(UniqueIdType.METRIC, uid);
}
@Override
public byte[] metricUID() {
if (edps[index].metricUIDs() == null) {
throw new IllegalStateException("Iterator UID was null for index " +
index + " and iterator " + iterator);
}
return edps[index].metricUIDs().iterator().next();
}
@Override
public Map<String, String> getTags() {
try {
return getTagsAsync().joinUninterruptibly();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Should never be here", e);
}
}
@Override
public Deferred<Map<String, String>> getTagsAsync() {
return Tags.getTagsAsync(tsdb, edps[index].tags());
}
@Override
public ByteMap<byte[]> getTagUids() {
return edps[index].tags();
}
@Override
public List<String> getAggregatedTags() {
try {
return getAggregatedTagsAsync().joinUninterruptibly();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Should never be here", e);
}
}
@Override
public Deferred<List<String>> getAggregatedTagsAsync() {
final ByteSet tagks = edps[index].aggregatedTags();
final List<String> aggregated_tags = new ArrayList<String>(tagks.size());
final List<Deferred<String>> names =
new ArrayList<Deferred<String>>(tagks.size());
for (final byte[] tagk : tagks) {
names.add(tsdb.getUidName(UniqueIdType.TAGK, tagk));
}
/** Adds the names to the aggregated_tags list */
final class ResolveCB implements Callback<List<String>, ArrayList<String>> {
@Override
public List<String> call(final ArrayList<String> names) throws Exception {
for (final String name : names) {
aggregated_tags.add(name);
}
return aggregated_tags;
}
}
return Deferred.group(names).addCallback(new ResolveCB());
}
@Override
public List<byte[]> getAggregatedTagUids() {
final List<byte[]> agg_tags = new ArrayList<byte[]>(
edps[index].aggregatedTags());
return agg_tags;
}
@Override
public List<String> getTSUIDs() {
// TODO Fix it up
return Collections.emptyList();
}
@Override
public List<Annotation> getAnnotations() {
// TODO Fix it up
return Collections.emptyList();
}
@Override
public int size() {
// TODO Estimate
return -1;
}
@Override
public int aggregatedSize() {
// TODO Estimate
return -1;
}
@Override
public SeekableView iterator() {
return new Iterator();
}
@Override
public long timestamp(int i) {
throw new UnsupportedOperationException();
}
@Override
public boolean isInteger(int i) {
throw new UnsupportedOperationException();
}
@Override
public long longValue(int i) {
throw new UnsupportedOperationException();
}
@Override
public double doubleValue(int i) {
throw new UnsupportedOperationException();
}
@Override
public int getQueryIndex() {
// TODO Fix it up
return 0;
}
/**
* Simple class that fills the local data point while iterating through the
* expression data points at the proper index.
*/
private class Iterator implements SeekableView {
/** A data pont to mutate as we iterate */
final MutableDataPoint dp = new MutableDataPoint();
@Override
public boolean hasNext() {
return iterator.hasNext(index);
}
@Override
public DataPoint next() {
iterator.next(index);
dp.reset(edps[index].timestamp(), edps[index].toDouble());
return dp;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void seek(long timestamp) {
throw new UnsupportedOperationException();
}
}
}