package org.kairosdb.core.http.rest; import com.google.common.collect.ImmutableList; import com.google.inject.Inject; import org.kairosdb.core.http.rest.json.ErrorResponse; import org.kairosdb.core.http.rest.json.JsonResponseBuilder; import org.kairosdb.core.http.rest.json.QueryParser; import org.kairosdb.core.http.rest.json.RollupResponse; import org.kairosdb.rollup.RollUpException; import org.kairosdb.rollup.RollUpTasksStore; import org.kairosdb.rollup.RollupTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; import static org.kairosdb.util.Preconditions.checkNotNullOrEmpty; @Path("/api/v1/rollups") public class RollUpResource { private static final Logger logger = LoggerFactory.getLogger(MetricsResource.class); static final String RESOURCE_URL = "/api/v1/rollups/"; private final QueryParser parser; private final RollUpTasksStore store; @Inject public RollUpResource(QueryParser parser, RollUpTasksStore store) { this.parser = checkNotNull(parser); this.store = checkNotNull(store); } @POST @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") public Response create(String json) { checkNotNullOrEmpty(json); try { RollupTask task = parser.parseRollupTask(json); store.write(ImmutableList.of(task)); ResponseBuilder responseBuilder = Response.status(Status.OK).entity(parser.getGson().toJson(createResponse(task))); setHeaders(responseBuilder); return responseBuilder.build(); } catch (BeanValidationException e) { JsonResponseBuilder builder = new JsonResponseBuilder(Status.BAD_REQUEST); return builder.addErrors(e.getErrorMessages()).build(); } catch (Exception e) { logger.error("Failed to add roll-up.", e); return setHeaders(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse(e.getMessage()))).build(); } } @GET @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") public Response list() { try { List<RollupTask> tasks = store.read(); StringBuilder json = new StringBuilder(); json.append('['); for (RollupTask task : tasks) { json.append(task.getJson()).append(","); } if (json.length() > 1) json.deleteCharAt(json.length() - 1); json.append(']'); ResponseBuilder responseBuilder = Response.status(Status.OK).entity(json.toString()); setHeaders(responseBuilder); return responseBuilder.build(); } catch (RollUpException e) { logger.error("Failed to list roll-ups.", e); return setHeaders(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse(e.getMessage()))).build(); } } @GET @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") @Path("{id}") public Response get(@PathParam("id") String id) { checkNotNullOrEmpty(id); try { ResponseBuilder responseBuilder; RollupTask found = null; List<RollupTask> tasks = store.read(); for (RollupTask task : tasks) { if (task.getId().equals(id)) { found = task; break; } } if (found != null) { responseBuilder = Response.status(Status.OK).entity(found.getJson()); } else { responseBuilder = Response.status(Status.NOT_FOUND).entity(new ErrorResponse("Resource not found for id " + id)); } setHeaders(responseBuilder); return responseBuilder.build(); } catch (RollUpException e) { logger.error("Failed to get roll-up.", e); return setHeaders(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse(e.getMessage()))).build(); } } @DELETE @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") @Path("{id}") public Response delete(@PathParam("id") String id) { try { checkNotNullOrEmpty(id); if (findExistingTask(id) != null) { store.remove(id); return setHeaders(Response.status(Status.NO_CONTENT)).entity("").build(); } else { ResponseBuilder responseBuilder = Response.status(Status.NOT_FOUND).entity(new ErrorResponse("Resource not found for id " + id)); setHeaders(responseBuilder); return responseBuilder.build(); } } catch (RollUpException e) { logger.error("Failed to delete roll-up.", e); return setHeaders(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse(e.getMessage()))).build(); } } @PUT @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") @Path("{id}") public Response update(@PathParam("id") String id, String json) { checkNotNullOrEmpty(id); checkNotNullOrEmpty(json); try { ResponseBuilder responseBuilder; if (findExistingTask(id) == null) { responseBuilder = Response.status(Status.NOT_FOUND).entity(new ErrorResponse("Resource not found for id " + id)); } else { RollupTask task = parser.parseRollupTask(json); RollupTask updatedTask = new RollupTask(id, task.getName(), task.getExecutionInterval(), task.getRollups(), task.getJson()); store.write(ImmutableList.of(updatedTask)); responseBuilder = Response.status(Status.OK).entity(parser.getGson().toJson(createResponse(updatedTask))); } setHeaders(responseBuilder); return responseBuilder.build(); } catch (BeanValidationException e) { JsonResponseBuilder builder = new JsonResponseBuilder(Status.BAD_REQUEST); return builder.addErrors(e.getErrorMessages()).build(); } catch (Exception e) { logger.error("Failed to add roll-up.", e); return setHeaders(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new ErrorResponse(e.getMessage()))).build(); } } private RollupResponse createResponse(RollupTask task) { return new RollupResponse(task.getId(), task.getName(), RESOURCE_URL + task.getId()); } private RollupTask findExistingTask(String id) throws RollUpException { List<RollupTask> tasks = store.read(); for (RollupTask task : tasks) { if (task.getId().equals(id)) { return task; } } return null; } private ResponseBuilder setHeaders(ResponseBuilder responseBuilder) { responseBuilder.header("Access-Control-Allow-Origin", "*"); responseBuilder.header("Pragma", "no-cache"); responseBuilder.header("Cache-Control", "no-cache"); responseBuilder.header("Expires", 0); return (responseBuilder); } }