/*
* Copyright (c) 2008-2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.resource;
import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.*;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.api.service.impl.resource.utils.StatRetriever;
import com.emc.storageos.db.client.TimeSeriesMetadata;
import com.emc.storageos.db.client.TimeSeriesMetadata.TimeBucket;
import com.emc.storageos.security.authorization.CheckPermission;
import com.emc.storageos.security.authorization.Role;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
@Path("/metering")
public class MeteringService extends ResourceService {
private StatRetriever _statRetriever;
final private Logger _logger = LoggerFactory.getLogger(MeteringService.class);
/**
* formats to be used to parse supported time bucket strings
*/
public static final String HOUR_BUCKET_TIME_FORMAT = "yyyy-MM-dd'T'HH";
public static final String MINUTE_BUCKET_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm";
public static final String BAD_TIMEBUCKET_MSG = "Error: time_bucket parameter format supplied is not valid.\n"
+ "Acceptable formats: yyyy-MM-dd'T'HH , yyyy-MM-dd'T'HH:mm";
public StatRetriever getStatRetriever() {
return _statRetriever;
}
public void setStatRetriever(StatRetriever _statRetriever) {
this._statRetriever = _statRetriever;
}
/**
* Retrieves the bulk metering stats for all resources in a specified time bucket (minute or hour).
*
* @param time_bucket required Time bucket for retrieval of stats. Acceptable formats are: yyyy-MM-dd'T'HH for hour bucket,
* yyyy-MM-dd'T'HH:mm for minute bucket
* @brief List metering statistics for time period
* @return - Output stream of stats or an error status.
*/
@GET
@Path("/stats")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN })
public Response getStats(
@QueryParam("time_bucket") final String timeBucketParam,
@Context HttpHeaders header) {
_logger.debug("getStats: timebucket: {}", timeBucketParam);
MediaType mediaType = MediaType.APPLICATION_XML_TYPE;
List<MediaType> mTypes = header.getAcceptableMediaTypes();
if (mTypes != null) {
for (MediaType media : mTypes) {
if (media.equals(MediaType.APPLICATION_JSON_TYPE)
|| media.equals(MediaType.APPLICATION_XML_TYPE)) {
mediaType = media;
break;
}
}
}
DateTimeFormatter dfHourFormat = DateTimeFormat.forPattern(
HOUR_BUCKET_TIME_FORMAT).withZoneUTC();
DateTimeFormatter dfMinuteFormat = DateTimeFormat.forPattern(
MINUTE_BUCKET_TIME_FORMAT).withZoneUTC();
DateTime timeBucket = null;
TimeBucket granularity = TimeBucket.HOUR;
try {
// we reduce the length by 2 here to account for single quote in yyyy-MM-dd'T'HH format
if ((null != timeBucketParam) && (timeBucketParam.length() == HOUR_BUCKET_TIME_FORMAT.length() - 2)) {
timeBucket = dfHourFormat.parseDateTime(timeBucketParam);
granularity = TimeSeriesMetadata.TimeBucket.HOUR;
} else if ((null != timeBucketParam) && (timeBucketParam.length() == MINUTE_BUCKET_TIME_FORMAT
.length() - 2)) {
timeBucket = dfMinuteFormat.parseDateTime(timeBucketParam);
granularity = TimeSeriesMetadata.TimeBucket.MINUTE;
} else {
throw APIException.badRequests.invalidTimeBucket(timeBucketParam);
}
} catch (final IllegalArgumentException e) {
throw APIException.badRequests.invalidTimeBucket(timeBucketParam, e);
}
if (timeBucket == null) {
throw APIException.badRequests.invalidTimeBucket(timeBucketParam);
}
return Response.ok(
getStreamData(timeBucket, granularity, mediaType),
mediaType).build();
}
/**
* Retrieves the bulk metering statistics for the given query params.
*
* @param timeBucket
* - time_bucket for retrieval of stats
* @param granularity
* - granularity can be HOUR or MINUTE
* @param mediaType
* - mediaType application/xml (default) or application/json
* @return StreamingOuput() - produces StreamingOutput of Stats
*/
private StreamingOutput getStreamData(final DateTime timeBucket,
final TimeBucket granularity, final MediaType mediaType) {
return new StreamingOutput() {
@Override
public void write(OutputStream outputStream) {
PrintWriter out = new PrintWriter(new BufferedOutputStream(
outputStream));
try {
if (_statRetriever == null) {
throw APIException.internalServerErrors.noMeteringStats();
}
_statRetriever.getBulkStats(timeBucket, granularity,
mediaType, out);
} catch (final Exception e) {
throw APIException.internalServerErrors.meteringStatsError(e.getMessage(), e);
} finally {
out.close();
}
}
};
}
}