/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; 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.EventRetriever; import com.emc.storageos.api.service.impl.resource.utils.MarshallingExcetion; 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; /** * Monitoring event resource implementation */ @Path("/monitoring") public class MonitoringService extends ResourceService { final private Logger _logger = LoggerFactory.getLogger(MonitoringService.class); private EventRetriever _eventRetriever; /** * 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"; /** * getter */ public EventRetriever getEventRetriever() { return _eventRetriever; } /** * setter */ public void setEventRetriever(EventRetriever eventRetriever) { _eventRetriever = eventRetriever; } /** * Retrieves the bulk events and alerts in a specified time bucket (minute or hour). * * @param time_bucket required Time bucket for retrieval of events. Acceptable formats are: yyyy-MM-dd'T'HH for hour bucket, * yyyy-MM-dd'T'HH:mm for minute bucket * @brief List events and alerts for time period * @return Output stream of events or an error status. */ @GET @Path("/events") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN }) public Response getEvents( @QueryParam("time_bucket") final String timeBucketParam, @Context HttpHeaders header) { _logger.debug("getEvents: timebucket: {}", timeBucketParam); MediaType mType = 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)) { mType = media; break; } } } // try two time formats which are supported DateTimeFormatter hourBucketFormat = DateTimeFormat.forPattern(HOUR_BUCKET_TIME_FORMAT) .withZoneUTC(); DateTimeFormatter minuteBucketFormat = DateTimeFormat.forPattern(MINUTE_BUCKET_TIME_FORMAT) .withZoneUTC(); DateTime timeBucket = null; TimeSeriesMetadata.TimeBucket timeBucketGran = TimeSeriesMetadata.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 = hourBucketFormat.parseDateTime(timeBucketParam); timeBucketGran = TimeSeriesMetadata.TimeBucket.HOUR; } else if ((null != timeBucketParam) && (timeBucketParam.length() == MINUTE_BUCKET_TIME_FORMAT.length() - 2)) { timeBucket = minuteBucketFormat.parseDateTime(timeBucketParam); timeBucketGran = 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( getStreamOutput(timeBucket, timeBucketGran, mType), mType).build(); } /** * Return an output stream object as http response entity so that the client could stream potentially large response. * * @param timeBucket * - the time bucket to retrieve events. * @param timeBucketGran * - granularity of the time bucket, can be hour or minute. * @param mediaType * - media type of the response. * @return * - the stream object from which client retrieves response message body. */ private StreamingOutput getStreamOutput(final DateTime timeBucket, final TimeBucket timeBucketGran, final MediaType mediaType) { return new StreamingOutput() { @Override public void write(OutputStream outputStream) { BufferedWriter out = new BufferedWriter(new OutputStreamWriter(outputStream)); try { if (_eventRetriever == null) { throw APIException.internalServerErrors.noEventRetriever(); } _eventRetriever.getBulkEvents(timeBucket, timeBucketGran, mediaType, out); } catch (MarshallingExcetion e) { _logger.error("retrieving event error", e); } catch (final Exception e) { throw APIException.internalServerErrors.eventRetrieverError(e.getMessage(), e); } finally { try { out.close(); } catch (IOException e) { _logger.error("stream close error", e); } } } }; } }