package com.signalfx.metrics.connection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.InputStreamEntity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.signalfx.common.proto.ProtocolBufferStreamingInputStream;
import com.signalfx.endpoint.SignalFxReceiverEndpoint;
import com.signalfx.metrics.SignalFxMetricsException;
import com.signalfx.metrics.protobuf.SignalFxProtocolBuffers;
public class HttpDataPointProtobufReceiverConnection
extends AbstractHttpDataPointProtobufReceiverConnection {
public HttpDataPointProtobufReceiverConnection(
SignalFxReceiverEndpoint endpoint, int timeoutMs,
HttpClientConnectionManager httpClientConnectionManager) {
super(endpoint, timeoutMs, httpClientConnectionManager);
}
@Override
protected HttpEntity getEntityForVersion(List<SignalFxProtocolBuffers.DataPoint> dataPoints) {
return new InputStreamEntity(
new ProtocolBufferStreamingInputStream<SignalFxProtocolBuffers.DataPoint>(
dataPoints.iterator()), PROTO_TYPE);
}
@Override
protected String getEndpointForAddDatapoints() {
return "/v1/datapoint";
}
@Override
public Map<String, Boolean> registerMetrics(String auth,
Map<String, SignalFxProtocolBuffers.MetricType> metricTypes)
throws SignalFxMetricsException {
Map<String, Boolean> res = new HashMap<String, Boolean>();
for (Map.Entry<String, SignalFxProtocolBuffers.MetricType> i : metricTypes.entrySet()) {
res.put(i.getKey(), false);
}
if (metricTypes.isEmpty()) {
return res;
}
List<Map<String, String>> postBodyList = new ArrayList<Map<String, String>>(
metricTypes.size());
for (Map.Entry<String, SignalFxProtocolBuffers.MetricType> entity : metricTypes
.entrySet()) {
postBodyList.add(ImmutableMap
.of("sf_metric", entity.getKey(), "sf_metricType",
entity.getValue().toString()));
}
final byte[] map_as_json;
try {
map_as_json = MAPPER.writeValueAsBytes(postBodyList);
} catch (JsonProcessingException e) {
throw new SignalFxMetricsException("Unable to write protocol buffer", e);
}
String body = "";
try {
CloseableHttpResponse resp = null;
try {
resp = postToEndpoint(auth,
new ByteArrayEntity(map_as_json, JSON_TYPE), "/v1/metric?bulkupdate=true");
try {
body = IOUtils.toString(resp.getEntity().getContent());
} catch (IOException e) {
throw new SignalFxMetricsException("Unable to get reponse content",
e);
}
if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new SignalFxMetricsException("Invalid status code "
+ resp.getStatusLine().getStatusCode() + ": " + body);
}
List<Map<String, String>> respObject =
new ObjectMapper().readValue(body.getBytes(),
new TypeReference<List<Map<String, String>>>() {
});
if (respObject.size() != metricTypes.size()) {
throw new SignalFxMetricsException(
String.format("json map mismatch: post_body=%s, resp=%s",
new String(map_as_json), body));
}
for (int i = 0; i < respObject.size(); i++) {
Map<String, String> m = respObject.get(i);
if (!m.containsKey("code") || "409".equals(m.get("code").toString())) {
res.put(postBodyList.get(i).get("sf_metric"), true);
}
}
} finally {
if (resp != null) {
resp.close();
}
}
} catch (IOException e) {
throw new SignalFxMetricsException(
String.format("post_body=%s, resp=%s", new String(map_as_json), body), e);
}
return res;
}
}