package com.baidubce.services.tsdb;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.zip.GZIPOutputStream;
import com.baidubce.AbstractBceClient;
import com.baidubce.BceClientConfiguration;
import com.baidubce.BceClientException;
import com.baidubce.auth.SignOptions;
import com.baidubce.http.Headers;
import com.baidubce.http.HttpMethodName;
import com.baidubce.http.handler.BceErrorResponseHandler;
import com.baidubce.http.handler.BceJsonResponseHandler;
import com.baidubce.http.handler.BceMetadataResponseHandler;
import com.baidubce.http.handler.HttpResponseHandler;
import com.baidubce.internal.InternalRequest;
import com.baidubce.internal.RestartableInputStream;
import com.baidubce.model.AbstractBceRequest;
import com.baidubce.services.tsdb.model.WriteDatapointsRequest;
import com.baidubce.util.HttpUtils;
import com.baidubce.util.JsonUtils;
/**
* Provides the client for accessing the Tsdb(Time series database) api.
*/
public abstract class AbstractTsdbBceClient extends AbstractBceClient {
private static final String VERSION = "v1";
private static final String[] HEADERS_TO_SIGN = { Headers.HOST };
private static final String DEFAULT_ENCODING = "UTF-8";
private static final String CONTENT_TYPE = "application/json;charset=UTF-8";
private static final String GZIP = "gzip";
private static final String UTF8 = "UTF-8";
/**
* Responsible for handling HttpResponse from all Tsdb service calls.
*/
protected static final HttpResponseHandler[] TSDB_HANDLERS = new HttpResponseHandler[] {
new BceMetadataResponseHandler(), new BceErrorResponseHandler(), new BceJsonResponseHandler() };
public AbstractTsdbBceClient(BceClientConfiguration config, HttpResponseHandler[] responseHandlers) {
super(config, responseHandlers);
}
protected byte[] toGzipBytes(WriteDatapointsRequest writeDatapointsRequest) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = null;
try {
gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
gzipOutputStream.write(JsonUtils.toJsonString(writeDatapointsRequest).getBytes(UTF8));
} catch (IOException e) {
throw new BceClientException("Create gzip bytes failed.", e);
} finally {
if (gzipOutputStream != null) {
try {
gzipOutputStream.close();
} catch (IOException e) {
throw new BceClientException("Close gzip stream failed.", e);
}
}
try {
byteArrayOutputStream.close();
} catch (IOException e) {
throw new BceClientException("Close byte stream failed.", e);
}
}
return byteArrayOutputStream.toByteArray();
}
protected InternalRequest createRequest(AbstractBceRequest bceRequest, HttpMethodName httpMethod,
String... pathVariables) {
return createRequest(this.getEndpoint(), bceRequest, httpMethod, null, pathVariables);
}
/**
* Creates and initializes a new request object for the specified resource.
*
* @param endpoint The endpoint to request.
* @param bceRequest The original BCE request created by the user.
* @param httpMethod The HTTP method to use when sending the request.
* @param signOptions The options for signature.
* @param pathVariables The optional variables used in the URI path.
* @return A new request object populated with endpoint, resource path and specific parameters to send.
*/
protected InternalRequest createRequest(URI endpoint, AbstractBceRequest bceRequest, HttpMethodName httpMethod,
SignOptions signOptions, String... pathVariables) {
List<String> path = new ArrayList<String>();
path.add(VERSION);
if (pathVariables != null) {
for (String pathVariable : pathVariables) {
path.add(pathVariable);
}
}
URI uri = HttpUtils.appendUri(endpoint, path.toArray(new String[path.size()]));
InternalRequest request = new InternalRequest(httpMethod, uri);
if (signOptions == null) {
signOptions = new SignOptions();
signOptions.setHeadersToSign(new HashSet<String>(Arrays.asList(HEADERS_TO_SIGN)));
}
signOptions.setTimestamp(getTimestampInThisMinute());
request.setSignOptions(signOptions);
request.setCredentials(bceRequest.getRequestCredentials());
return request;
}
protected Date getTimestampInThisMinute() {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 0);
return calendar.getTime();
}
protected void fillInHeadAndBody(AbstractBceRequest bceRequest, InternalRequest request) {
byte[] content = toJson(bceRequest);
request.addHeader(Headers.CONTENT_LENGTH, Integer.toString(content.length));
request.addHeader(Headers.CONTENT_TYPE, CONTENT_TYPE);
request.setContent(RestartableInputStream.wrap(content));
}
protected void fillInHeadAndBodyForGzip(InternalRequest request, byte[] bytes) {
request.addHeader(Headers.CONTENT_LENGTH, String.valueOf(bytes.length));
request.addHeader(Headers.CONTENT_TYPE, CONTENT_TYPE);
request.setContent(RestartableInputStream.wrap(bytes));
request.addHeader(Headers.CONTENT_ENCODING, GZIP);
}
protected byte[] toJson(AbstractBceRequest bceRequest) {
String jsonStr = JsonUtils.toJsonString(bceRequest);
try {
return jsonStr.getBytes(DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
throw new BceClientException("Fail to get UTF-8 bytes", e);
}
}
/**
* Converts the specified request object into a URL, containing all the
* specified parameters, the specified request endpoint, etc.
*
* @param request The request to convert into a URL.
* @return A new URL representing the specified request.
*/
protected URL convertRequestToUrl(InternalRequest request) {
String resourcePath = HttpUtils.normalizePath(request.getUri().getPath());
// Removed the padding "/" that was already added into the request's resource path.
if (resourcePath.startsWith("/")) {
resourcePath = resourcePath.substring(1);
}
// Some http client libraries (e.g. Apache HttpClient) cannot handle
// consecutive "/"s between URL authority and path components.
// So we escape "////..." into "/%2F%2F%2F...", in the same way as how
// we treat consecutive "/"s in AmazonS3Client#presignRequest(...)
String urlPath = "/" + resourcePath;
urlPath = urlPath.replaceAll("(?<=/)/", "%2F");
String urlString = this.getEndpoint() + urlPath;
boolean firstParam = true;
for (String param : request.getParameters().keySet()) {
if (firstParam) {
urlString += "?";
firstParam = false;
} else {
urlString += "&";
}
String value = request.getParameters().get(param);
urlString += param + "=" + HttpUtils.normalize(value);
}
String authorization = request.getHeaders().get(Headers.AUTHORIZATION);
if (authorization != null) {
if (firstParam) {
urlString += "?";
} else {
urlString += "&";
}
urlString += "authorization" + "=" + HttpUtils.normalize(authorization);
}
try {
return new URL(urlString);
} catch (MalformedURLException e) {
throw new BceClientException("Unable to convert request to well formed URL: " + e.getMessage(), e);
}
}
}