package org.yamcs.web.rest.archive; import java.io.IOException; import org.yamcs.TimeInterval; import org.yamcs.YamcsException; import org.yamcs.archive.TagDb; import org.yamcs.archive.TagReceiver; import org.yamcs.protobuf.Rest.CreateTagRequest; import org.yamcs.protobuf.Rest.EditTagRequest; import org.yamcs.protobuf.Rest.ListTagsResponse; import org.yamcs.protobuf.SchemaRest; import org.yamcs.protobuf.SchemaYamcs; import org.yamcs.protobuf.Yamcs.ArchiveTag; import org.yamcs.web.BadRequestException; import org.yamcs.web.HttpException; import org.yamcs.web.InternalServerErrorException; import org.yamcs.web.NotFoundException; import org.yamcs.web.rest.RestHandler; import org.yamcs.web.rest.RestRequest; import org.yamcs.web.rest.RestRequest.IntervalResult; import org.yamcs.web.rest.Route; import org.yamcs.yarch.YarchDatabase; import org.yamcs.yarch.YarchException; public class ArchiveTagRestHandler extends RestHandler { @Route(path = "/api/archive/:instance/tags", method = "GET") public void listTags(RestRequest req) throws HttpException { String instance = verifyInstance(req, req.getRouteParam("instance")); TagDb tagDb = getTagDb(instance); IntervalResult ir = req.scanForInterval(); TimeInterval interval = ir.asTimeInterval(); // Build response with a callback from the TagDb, this is all happening on // the same thread. ListTagsResponse.Builder responseb = ListTagsResponse.newBuilder(); try { tagDb.getTags(interval, new TagReceiver() { @Override public void onTag(ArchiveTag tag) { responseb.addTag(tag); } @Override public void finished() {} }); } catch (IOException e) { throw new InternalServerErrorException("Could not load tags", e); } completeOK(req, responseb.build(), SchemaRest.ListTagsResponse.WRITE); } @Route(path = "/api/archive/:instance/tags/:tagTime/:tagId", method = "GET") public void getTag(RestRequest req) throws HttpException { String instance = verifyInstance(req, req.getRouteParam("instance")); TagDb tagDb = getTagDb(instance); long tagTime = req.getDateRouteParam("tagTime"); int tagId = req.getIntegerRouteParam("tagId"); ArchiveTag tag = verifyTag(req, tagDb, tagTime, tagId); completeOK(req, tag, SchemaYamcs.ArchiveTag.WRITE); } /** * Adds a new tag. The newly added tag is returned as a response so the user * knows the assigned id. */ @Route(path = "/api/archive/:instance/tags", method = "POST") public void createTag(RestRequest req) throws HttpException { String instance = verifyInstance(req, req.getRouteParam("instance")); TagDb tagDb = getTagDb(instance); CreateTagRequest request = req.bodyAsMessage(SchemaRest.CreateTagRequest.MERGE).build(); if (!request.hasName()) throw new BadRequestException("Name is required"); // Translate to yamcs-api ArchiveTag.Builder tagb = ArchiveTag.newBuilder().setName(request.getName()); if (request.hasStart()) tagb.setStart(RestRequest.parseTime(request.getStart())); if (request.hasStop()) tagb.setStop(RestRequest.parseTime(request.getStop())); if (request.hasDescription()) tagb.setDescription(request.getDescription()); if (request.hasColor()) tagb.setColor(request.getColor()); // Do the insert ArchiveTag newTag; try { newTag = tagDb.insertTag(tagb.build()); } catch (IOException e) { throw new InternalServerErrorException(e); } // Echo back the tag, with its assigned ID completeOK(req, newTag, SchemaYamcs.ArchiveTag.WRITE); } /** * Updates an existing tag. Returns the updated tag */ @Route(path = "/api/archive/:instance/tags/:tagTime/:tagId", method = { "PATCH", "PUT", "POST" }) public void updateTag(RestRequest req) throws HttpException { String instance = verifyInstance(req, req.getRouteParam("instance")); TagDb tagDb = getTagDb(instance); ArchiveTag tag = verifyTag(req, tagDb, req.getDateRouteParam("tagTime"), req.getIntegerRouteParam("tagId")); EditTagRequest request = req.bodyAsMessage(SchemaRest.EditTagRequest.MERGE).build(); // Patch the existing tag ArchiveTag.Builder tagb = ArchiveTag.newBuilder(tag); if (request.hasName()) tagb.setName(request.getName()); if (request.hasStart()) tagb.setStart(RestRequest.parseTime(request.getStart())); if (request.hasStop()) tagb.setStop(RestRequest.parseTime(request.getStop())); if (request.hasDescription()) tagb.setDescription(request.getDescription()); if (request.hasColor()) tagb.setColor(request.getColor()); // Override with query params if (req.hasQueryParameter("name")) tagb.setName(req.getQueryParameter("name")); if (req.hasQueryParameter("start")) tagb.setStart(RestRequest.parseTime(req.getQueryParameter("start"))); if (req.hasQueryParameter("stop")) tagb.setStop(RestRequest.parseTime(req.getQueryParameter("stop"))); if (req.hasQueryParameter("description")) tagb.setDescription(req.getQueryParameter("description")); if (req.hasQueryParameter("color")) tagb.setColor(req.getQueryParameter("color")); // Persist the update ArchiveTag updatedTag; try { long tagTime = tag.hasStart() ? tag.getStart() : 0; updatedTag = tagDb.updateTag(tagTime, tag.getId(), tagb.build()); } catch (YamcsException e) { throw new InternalServerErrorException(e); } catch (IOException e) { throw new InternalServerErrorException(e); } completeOK(req, updatedTag, SchemaYamcs.ArchiveTag.WRITE); } /** * Deletes the identified tag. Returns the deleted tag */ @Route(path = "/api/archive/:instance/tags/:tagTime/:tagId", method = "DELETE") public void deleteTag(RestRequest req, TagDb tagDb, long tagTime, int tagId) throws HttpException { ArchiveTag deletedTag; try { deletedTag = tagDb.deleteTag(tagTime, tagId); } catch (YamcsException e) { // Delete-tag returns an exception when it's not found throw new NotFoundException(req); } catch (IOException e) { throw new InternalServerErrorException(e); } completeOK(req, deletedTag, SchemaYamcs.ArchiveTag.WRITE); } private static TagDb getTagDb(String yamcsInstance) throws HttpException { try { return YarchDatabase.getInstance(yamcsInstance).getDefaultStorageEngine().getTagDb(); } catch (YarchException e) { throw new InternalServerErrorException("Could not load Tag DB", e); } } private ArchiveTag verifyTag(RestRequest req, TagDb tagDb, long tagTime, int tagId) throws HttpException { if (tagId < 1) throw new BadRequestException("Invalid tag ID"); ArchiveTag tag; try { tag = tagDb.getTag(tagTime, tagId); } catch (IOException e) { throw new InternalServerErrorException(e); } if (tag == null) { throw new NotFoundException(req, "No tag for ID (" + tagTime + ", " + tagId + ")"); } else { return tag; } } }