/*
* Copyright (C) 2015 SoftIndex LLC.
*
* 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 io.datakernel.cube.http;
import com.google.gson.Gson;
import io.datakernel.async.ForwardingResultCallback;
import io.datakernel.async.ResultCallback;
import io.datakernel.bytebuf.ByteBufStrings;
import io.datakernel.cube.CubeQuery;
import io.datakernel.cube.ICube;
import io.datakernel.cube.QueryResult;
import io.datakernel.eventloop.Eventloop;
import io.datakernel.exception.ParseException;
import io.datakernel.http.*;
import java.lang.reflect.Type;
import java.net.URI;
import java.util.Map;
import static com.google.common.collect.Maps.newLinkedHashMap;
import static io.datakernel.cube.http.Utils.*;
public final class CubeHttpClient implements ICube {
private final Eventloop eventloop;
private final String url;
private final IAsyncHttpClient httpClient;
private Gson gson;
private final Map<String, Type> attributeTypes = newLinkedHashMap();
private final Map<String, Type> measureTypes = newLinkedHashMap();
private CubeHttpClient(Eventloop eventloop, IAsyncHttpClient httpClient,
String url) {
this.eventloop = eventloop;
this.url = url.replaceAll("/$", "");
this.httpClient = httpClient;
this.gson = createGsonBuilder(attributeTypes, measureTypes).create(); // TODO support of external GsonBuilder
}
public static CubeHttpClient create(Eventloop eventloop, AsyncHttpClient httpClient, String cubeServletUrl) {
return new CubeHttpClient(eventloop, httpClient, cubeServletUrl);
}
public static CubeHttpClient create(Eventloop eventloop, AsyncHttpClient httpClient, URI cubeServletUrl) {
return create(eventloop, httpClient, cubeServletUrl.toString());
}
public CubeHttpClient withAttribute(String attribute, Type type) {
attributeTypes.put(attribute, type);
return this;
}
public CubeHttpClient withMeasure(String measureId, Class<?> type) {
measureTypes.put(measureId, type);
return this;
}
@Override
public Map<String, Type> getAttributeTypes() {
return attributeTypes;
}
@Override
public Map<String, Type> getMeasureTypes() {
return measureTypes;
}
@Override
public void query(CubeQuery query, final ResultCallback<QueryResult> callback) {
httpClient.send(buildRequest(query), new ForwardingResultCallback<HttpResponse>(callback) {
@Override
public void onResult(HttpResponse httpResponse) {
String response;
try {
response = ByteBufStrings.decodeUtf8(httpResponse.getBody()); // TODO getBodyAsString
} catch (ParseException e) {
callback.setException(new ParseException("Cube HTTP query failed. Invalid data received", e));
return;
}
if (httpResponse.getCode() != 200) {
callback.setException(new ParseException("Cube HTTP query failed. Response code: "
+ httpResponse.getCode() + " Body: " + response));
return;
}
QueryResult result = gson.fromJson(response, QueryResult.class);
callback.setResult(result);
}
});
}
private HttpRequest buildRequest(CubeQuery query) {
Map<String, String> urlParams = newLinkedHashMap();
urlParams.put(ATTRIBUTES_PARAM, JOINER.join(query.getAttributes()));
urlParams.put(MEASURES_PARAM, JOINER.join(query.getMeasures()));
urlParams.put(WHERE_PARAM, gson.toJson(query.getWhere()));
urlParams.put(SORT_PARAM, formatOrderings(query.getOrderings()));
urlParams.put(HAVING_PARAM, gson.toJson(query.getHaving()));
if (query.getLimit() != null)
urlParams.put(LIMIT_PARAM, query.getLimit().toString());
if (query.getOffset() != null)
urlParams.put(OFFSET_PARAM, query.getOffset().toString());
String url = this.url + "/" + "?" + HttpUtils.urlQueryString(urlParams);
return HttpRequest.get(url);
}
}