Skip to content

Commit

Permalink
Merge pull request #188 from jsanda/HWKMETRICS-41
Browse files Browse the repository at this point in the history
Do not return null from core API methods
  • Loading branch information
tsegismont committed Mar 25, 2015
2 parents 7b5fc00 + e5a8f55 commit 5a72f93
Show file tree
Hide file tree
Showing 24 changed files with 859 additions and 923 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,17 @@
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;

import org.hawkular.metrics.api.jaxrs.callback.SimpleDataCallback;
import org.hawkular.metrics.api.jaxrs.callback.TenantCreatedCallback;
import org.hawkular.metrics.core.api.MetricsService;
import org.hawkular.metrics.core.api.Tenant;

import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import org.hawkular.metrics.api.jaxrs.callback.TenantCreatedCallback;
import org.hawkular.metrics.api.jaxrs.util.ApiUtils;
import org.hawkular.metrics.core.api.MetricsService;
import org.hawkular.metrics.core.api.Tenant;

/**
* @author Thomas Segismont
Expand Down Expand Up @@ -98,7 +97,9 @@ public void createTenant(
response = ApiError.class)
})
public void findTenants(@Suspended AsyncResponse asyncResponse) {
ListenableFuture<List<Tenant>> tenantsFuture = metricsService.getTenants();
Futures.addCallback(tenantsFuture, new SimpleDataCallback<>(asyncResponse));
ApiUtils.executeAsync(asyncResponse, () -> {
ListenableFuture<List<Tenant>> future = metricsService.getTenants();
return Futures.transform(future, ApiUtils.MAP_COLLECTION);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
*/
package org.hawkular.metrics.api.jaxrs.callback;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;

import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.core.Response;

Expand All @@ -28,7 +32,29 @@ public SimpleDataCallback(AsyncResponse asyncResponse) {
@Override
public void onSuccess(Object responseData) {
if (responseData == null) {
asyncResponse.resume(Response.noContent().build());
asyncResponse.resume(Response.noContent().build());
} else if (responseData instanceof Optional) {
Optional optional = (Optional) responseData;
if (optional.isPresent()) {
Object value = optional.get();
asyncResponse.resume(Response.ok(value).build());
} else {
asyncResponse.resume(Response.noContent().build());
}
} else if (responseData instanceof Collection) {
Collection collection = (Collection) responseData;
if (collection.isEmpty()) {
asyncResponse.resume(Response.noContent().build());
} else {
asyncResponse.resume(Response.ok(collection).build());
}
} else if (responseData instanceof Map) {
Map map = (Map) responseData;
if (map.isEmpty()) {
asyncResponse.resume(Response.noContent().build());
} else {
asyncResponse.resume(Response.ok(map).build());
}
} else {
asyncResponse.resume(Response.ok(responseData).build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,14 @@
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;

import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.hawkular.metrics.api.jaxrs.callback.NoDataCallback;
import org.hawkular.metrics.api.jaxrs.ApiError;
import org.hawkular.metrics.api.jaxrs.influx.query.InfluxQueryParseTreeWalker;
import org.hawkular.metrics.api.jaxrs.influx.query.parse.InfluxQueryParser;
import org.hawkular.metrics.api.jaxrs.influx.query.parse.InfluxQueryParser.QueryContext;
Expand All @@ -66,6 +72,7 @@
import org.hawkular.metrics.api.jaxrs.influx.query.validation.QueryValidator;
import org.hawkular.metrics.api.jaxrs.influx.write.validation.InfluxObjectValidator;
import org.hawkular.metrics.api.jaxrs.influx.write.validation.InvalidObjectException;
import org.hawkular.metrics.api.jaxrs.util.ApiUtils;
import org.hawkular.metrics.api.jaxrs.util.StringValue;
import org.hawkular.metrics.core.api.Metric;
import org.hawkular.metrics.core.api.MetricId;
Expand All @@ -78,13 +85,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.FluentIterable;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;

/**
* Some support for InfluxDB clients like Grafana.
*
Expand Down Expand Up @@ -114,38 +114,39 @@ public class InfluxSeriesHandler {
@Consumes(APPLICATION_JSON)
public void write(@Suspended AsyncResponse asyncResponse, @PathParam("tenantId") String tenantId,
List<InfluxObject> influxObjects) {
if (influxObjects == null) {
asyncResponse.resume(Response.status(Status.BAD_REQUEST).entity("Null objects").build());
return;
}
try {
objectValidator.validateInfluxObjects(influxObjects);
} catch (InvalidObjectException e) {
asyncResponse.resume(Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build());
return;
}
List<NumericMetric> numericMetrics = FluentIterable.from(influxObjects) //
.transform(influxObject -> {
List<String> influxObjectColumns = influxObject.getColumns();
int valueColumnIndex = influxObjectColumns.indexOf("value");
List<List<?>> influxObjectPoints = influxObject.getPoints();
NumericMetric numericMetric = new NumericMetric(tenantId, new MetricId(influxObject.getName()));
for (List<?> point : influxObjectPoints) {
double value;
long timestamp;
if (influxObjectColumns.size() == 1) {
timestamp = System.currentTimeMillis();
value = ((Number) point.get(0)).doubleValue();
} else {
timestamp = ((Number) point.get((valueColumnIndex + 1) % 2)).longValue();
value = ((Number) point.get(valueColumnIndex)).doubleValue();
}
numericMetric.addData(new NumericData(timestamp, value));
}
return numericMetric;
}).toList();
ListenableFuture<Void> future = metricsService.addNumericData(numericMetrics);
Futures.addCallback(future, new NoDataCallback<Void>(asyncResponse));

ApiUtils.executeAsync(asyncResponse, () -> {
if (influxObjects == null) {
return ApiUtils.badRequest(new ApiError("Null objects"));
}
try {
objectValidator.validateInfluxObjects(influxObjects);
} catch (InvalidObjectException e) {
return ApiUtils.badRequest(new ApiError(e.getMessage()));
}
List<NumericMetric> numericMetrics = FluentIterable.from(influxObjects) //
.transform(influxObject -> {
List<String> influxObjectColumns = influxObject.getColumns();
int valueColumnIndex = influxObjectColumns.indexOf("value");
List<List<?>> influxObjectPoints = influxObject.getPoints();
NumericMetric numericMetric = new NumericMetric(tenantId, new MetricId(influxObject.getName()));
for (List<?> point : influxObjectPoints) {
double value;
long timestamp;
if (influxObjectColumns.size() == 1) {
timestamp = System.currentTimeMillis();
value = ((Number) point.get(0)).doubleValue();
} else {
timestamp = ((Number) point.get((valueColumnIndex + 1) % 2)).longValue();
value = ((Number) point.get(valueColumnIndex)).doubleValue();
}
numericMetric.addData(new NumericData(timestamp, value));
}
return numericMetric;
}).toList();
ListenableFuture<Void> future = metricsService.addNumericData(numericMetrics);
return Futures.transform(future, ApiUtils.MAP_VOID);
});
}

@GET
Expand Down Expand Up @@ -250,8 +251,8 @@ private void select(AsyncResponse asyncResponse, String tenantId, SelectQueryCon
if (idExists != Boolean.TRUE) {
return Futures.immediateFuture(null);
}
return metricsService.findData(new NumericMetric(tenantId, new MetricId(metric)),
timeInterval.getStartMillis(), timeInterval.getEndMillis());
return metricsService.findNumericData(tenantId, new MetricId(metric),
timeInterval.getStartMillis(), timeInterval.getEndMillis());
});
ListenableFuture<List<InfluxObject>> influxObjectTranslatorFuture = Futures.transform(loadMetricsFuture,
(List<NumericData> metrics) -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2014-2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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 org.hawkular.metrics.api.jaxrs.util;

import static java.util.stream.Collectors.toMap;

import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;

import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.core.Response;

import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.hawkular.metrics.api.jaxrs.ApiError;

/**
* @author jsanda
*/
public class ApiUtils {

private ApiUtils() {
}

public static final Function<Void, Response> MAP_VOID = v -> Response.ok().build();

public static final Function<Optional<?>, Response> MAP_VALUE = optional ->
optional.map(value -> Response.ok(value).build()).orElse(noContent());

public static final Function<Collection<?>, Response> MAP_COLLECTION = collection ->
collection.isEmpty() ? noContent() : Response.ok(collection).build();

public static final Function<Map<?, ?>, Response> MAP_MAP = map ->
map.isEmpty() ? noContent() : Response.ok(map).build();

public static Response noContent() {
return Response.noContent().build();
}

public static ListenableFuture<Response> emptyPayload() {
return badRequest(new ApiError("Payload is empty"));
}

public static ListenableFuture<Response> badRequest(ApiError error) {
return Futures.immediateFuture(Response.status(Response.Status.BAD_REQUEST).entity(error).build());
}

public static void executeAsync(AsyncResponse asyncResponse,
java.util.function.Supplier<ListenableFuture<Response>> supplier) {
ListenableFuture<Response> future = supplier.get();
Futures.addCallback(future, new FutureCallback<Response>() {
@Override
public void onSuccess(Response response) {
asyncResponse.resume(response);
}

@Override
public void onFailure(Throwable t) {
String msg = "Failed to perform operation due to an error: " + Throwables.getRootCause(t).getMessage();
asyncResponse.resume(Response.serverError().entity(new ApiError(msg)).build());
}
});
}

public static Map<String, String> decodeTags(String tags) {
return Arrays.stream(tags.split(","))
.map(s -> s.split(":"))
.collect(toMap(a -> a[0], a -> a[1]));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;

Expand Down Expand Up @@ -69,7 +70,7 @@ public interface MetricsService {

ListenableFuture<Void> createMetric(Metric<?> metric);

ListenableFuture<Metric<?>> findMetric(String tenantId, MetricType type, MetricId id);
ListenableFuture<Optional<Metric<?>>> findMetric(String tenantId, MetricType type, MetricId id);

ListenableFuture<List<Metric<?>>> findMetrics(String tenantId, MetricType type);

Expand All @@ -79,18 +80,15 @@ public interface MetricsService {

ListenableFuture<Void> addNumericData(List<NumericMetric> metrics);

ListenableFuture<NumericMetric> findNumericData(NumericMetric metric, long start, long end);
ListenableFuture<List<NumericData>> findNumericData(String tenantId, MetricId id, Long start, Long end);

ListenableFuture<BucketedOutput<NumericBucketDataPoint>> findNumericStats(
NumericMetric metric, long start, long end, Buckets buckets
);

/** Find and return raw metrics for {id} that have a timestamp between {start} and {end} */
ListenableFuture<List<NumericData>> findData(NumericMetric metric, long start, long end);

ListenableFuture<Void> addAvailabilityData(List<AvailabilityMetric> metrics);

ListenableFuture<AvailabilityMetric> findAvailabilityData(AvailabilityMetric metric, long start, long end);
ListenableFuture<List<Availability>> findAvailabilityData(String tenantId, MetricId id, long start, long end);

ListenableFuture<BucketedOutput<AvailabilityBucketDataPoint>> findAvailabilityStats(
AvailabilityMetric metric, long start, long end, Buckets buckets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,22 @@

import org.hawkular.metrics.core.api.Availability;
import org.hawkular.metrics.core.api.AvailabilityBucketDataPoint;
import org.hawkular.metrics.core.api.AvailabilityMetric;
import org.hawkular.metrics.core.api.Buckets;
import org.hawkular.metrics.core.api.MetricId;

/**
* A {@link BucketedOutputMapper} for {@link org.hawkular.metrics.core.api.AvailabilityMetric}.
*
* @author Thomas Segismont
*/
public class AvailabilityBucketedOutputMapper
extends BucketedOutputMapper<Availability, AvailabilityMetric, AvailabilityBucketDataPoint> {
extends BucketedOutputMapper<Availability, AvailabilityBucketDataPoint> {

/**
* @param buckets the bucket configuration
*/
public AvailabilityBucketedOutputMapper(Buckets buckets) {
super(buckets);
public AvailabilityBucketedOutputMapper(String tenantId, MetricId id, Buckets buckets) {
super(tenantId, id, buckets);
}

@Override
Expand Down

0 comments on commit 5a72f93

Please sign in to comment.