/* * 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.common.base.Charsets; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import io.datakernel.aggregation.AggregationPredicate; import io.datakernel.aggregation.QueryException; import io.datakernel.async.ForwardingResultCallback; import io.datakernel.async.ResultCallback; import io.datakernel.cube.Cube; 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 io.datakernel.util.Stopwatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Type; import java.util.List; import static io.datakernel.bytebuf.ByteBufStrings.wrapUtf8; import static io.datakernel.cube.http.Utils.*; import static io.datakernel.http.HttpMethod.GET; public final class ReportingServiceServlet implements AsyncServlet { protected final Logger logger = LoggerFactory.getLogger(ReportingServiceServlet.class); private static final Type LIST_OF_STRINGS = new TypeToken<List<String>>() {}.getType(); private static final Type ORDERINGS = new TypeToken<List<CubeQuery.Ordering>>() {}.getType(); private final Eventloop eventloop; private final ICube cube; private final Gson gson; private ReportingServiceServlet(Eventloop eventloop, ICube cube, Gson gson) { this.eventloop = eventloop; this.gson = gson; this.cube = cube; } public static ReportingServiceServlet create(Eventloop eventloop, ICube cube) { Gson gson = createGsonBuilder(cube.getAttributeTypes(), cube.getMeasureTypes()).create(); return new ReportingServiceServlet(eventloop, cube, gson); } public static MiddlewareServlet createRootServlet(Eventloop eventloop, ICube cube) { MiddlewareServlet middlewareServlet = MiddlewareServlet.create() .with(GET, "/", create(eventloop, cube)); if (cube instanceof Cube) { middlewareServlet = middlewareServlet .with(GET, "/consolidation-debug", ConsolidationDebugServlet.create((Cube) cube)); } return middlewareServlet; } @Override public void serve(final HttpRequest httpRequest, final ResultCallback<HttpResponse> callback) { logger.info("Received request: {}", httpRequest); try { final Stopwatch totalTimeStopwatch = Stopwatch.createStarted(); final CubeQuery cubeQuery = parseQuery(httpRequest); cube.query(cubeQuery, new ForwardingResultCallback<QueryResult>(callback) { @Override protected void onResult(QueryResult result) { Stopwatch resultProcessingStopwatch = Stopwatch.createStarted(); String json = gson.toJson(result); HttpResponse httpResponse = createResponse(json); logger.info("Processed request {} ({}) [totalTime={}, jsonConstruction={}]", httpRequest, cubeQuery, totalTimeStopwatch, resultProcessingStopwatch); callback.setResult(httpResponse); } }); } catch (ParseException e) { logger.error("Parse exception: " + httpRequest, e); callback.setException(e); } catch (QueryException e) { logger.error("Query exception: " + httpRequest, e); callback.setException(e); } } private static HttpResponse createResponse(String body) { HttpResponse response = HttpResponse.ok200(); response.setContentType(ContentType.of(MediaTypes.JSON, Charsets.UTF_8)); response.setBody(wrapUtf8(body)); response.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); return response; } @SuppressWarnings("unchecked") public CubeQuery parseQuery(HttpRequest request) throws ParseException { CubeQuery query = CubeQuery.create(); String parameter; parameter = request.getParameter(ATTRIBUTES_PARAM); if (parameter != null) query = query.withAttributes(SPLITTER.splitToList(parameter)); parameter = request.getParameter(MEASURES_PARAM); if (parameter != null) query = query.withMeasures(SPLITTER.splitToList(parameter)); parameter = request.getParameter(WHERE_PARAM); if (parameter != null) query = query.withWhere(gson.fromJson(parameter, AggregationPredicate.class)); parameter = request.getParameter(SORT_PARAM); if (parameter != null) query = query.withOrderings(parseOrderings(parameter)); parameter = request.getParameter(HAVING_PARAM); if (parameter != null) query = query.withHaving(gson.fromJson(parameter, AggregationPredicate.class)); parameter = request.getParameter(LIMIT_PARAM); if (parameter != null) query = query.withLimit(Integer.valueOf(parameter)); // TODO throws ParseException parameter = request.getParameter(OFFSET_PARAM); if (parameter != null) query = query.withOffset(Integer.valueOf(parameter)); return query; } }