package org.yamcs.web.rest.processor;
import java.util.UUID;
import org.yamcs.Processor;
import org.yamcs.commanding.CommandQueue;
import org.yamcs.commanding.CommandQueueManager;
import org.yamcs.commanding.PreparedCommand;
import org.yamcs.management.ManagementGpbHelper;
import org.yamcs.management.ManagementService;
import org.yamcs.protobuf.Commanding.CommandQueueEntry;
import org.yamcs.protobuf.Commanding.CommandQueueInfo;
import org.yamcs.protobuf.Commanding.QueueState;
import org.yamcs.protobuf.Rest.EditCommandQueueEntryRequest;
import org.yamcs.protobuf.Rest.EditCommandQueueRequest;
import org.yamcs.protobuf.Rest.ListCommandQueueEntries;
import org.yamcs.protobuf.Rest.ListCommandQueuesResponse;
import org.yamcs.protobuf.SchemaCommanding;
import org.yamcs.protobuf.SchemaRest;
import org.yamcs.web.BadRequestException;
import org.yamcs.web.HttpException;
import org.yamcs.web.NotFoundException;
import org.yamcs.web.rest.RestHandler;
import org.yamcs.web.rest.RestRequest;
import org.yamcs.web.rest.RestRequest.Option;
import org.yamcs.web.rest.Route;
public class ProcessorCommandQueueRestHandler extends RestHandler {
@Route(path = "/api/processors/:instance/:processor/cqueues", method = "GET")
public void listQueues(RestRequest req) throws HttpException {
Processor processor = verifyProcessor(req, req.getRouteParam("instance"), req.getRouteParam("processor"));
ListCommandQueuesResponse.Builder response = ListCommandQueuesResponse.newBuilder();
ManagementService managementService = ManagementService.getInstance();
CommandQueueManager mgr = managementService.getCommandQueueManager(processor);
mgr.getQueues().forEach(q -> response.addQueue(toCommandQueueInfo(req, q, true)));
completeOK(req, response.build(), SchemaRest.ListCommandQueuesResponse.WRITE);
}
@Route(path = "/api/processors/:instance/:processor/cqueues/:name", method = "GET")
public void getQueue(RestRequest req) throws HttpException {
Processor processor = verifyProcessor(req, req.getRouteParam("instance"), req.getRouteParam("processor"));
CommandQueueManager mgr = verifyCommandQueueManager(processor);
CommandQueue queue = verifyCommandQueue(req, mgr, req.getRouteParam("name"));
CommandQueueInfo info = toCommandQueueInfo(req, queue, true);
completeOK(req, info, SchemaCommanding.CommandQueueInfo.WRITE);
}
@Route(path = "/api/processors/:instance/:processor/cqueues/:name", method = { "PATCH", "PUT", "POST" })
public void editQueue(RestRequest req) throws HttpException {
Processor processor = verifyProcessor(req, req.getRouteParam("instance"), req.getRouteParam("processor"));
CommandQueueManager mgr = verifyCommandQueueManager(processor);
CommandQueue queue = verifyCommandQueue(req, mgr, req.getRouteParam("name"));
EditCommandQueueRequest body = req.bodyAsMessage(SchemaRest.EditCommandQueueRequest.MERGE).build();
String state = null;
if (body.hasState()) {
state = body.getState();
}
if (req.hasQueryParameter("state")) {
state = req.getQueryParameter("state");
}
CommandQueue updatedQueue = queue;
if (state != null) {
switch (state.toLowerCase()) {
case "disabled":
updatedQueue = mgr.setQueueState(queue.getName(), QueueState.DISABLED);
break;
case "enabled":
updatedQueue = mgr.setQueueState(queue.getName(), QueueState.ENABLED);
break;
case "blocked":
updatedQueue = mgr.setQueueState(queue.getName(), QueueState.BLOCKED);
break;
default:
throw new BadRequestException("Unsupported queue state '" + state + "'");
}
}
CommandQueueInfo qinfo = toCommandQueueInfo(req, updatedQueue, true);
completeOK(req, qinfo, SchemaCommanding.CommandQueueInfo.WRITE);
}
@Route(path = "/api/processors/:instance/:processor/cqueues/:name/entries", method = "GET")
public void listQueueEntries(RestRequest req) throws HttpException {
Processor processor = verifyProcessor(req, req.getRouteParam("instance"), req.getRouteParam("processor"));
CommandQueueManager mgr = verifyCommandQueueManager(processor);
CommandQueue queue = verifyCommandQueue(req, mgr, req.getRouteParam("name"));
ListCommandQueueEntries.Builder responseb = ListCommandQueueEntries.newBuilder();
for (PreparedCommand pc : queue.getCommands()) {
CommandQueueEntry qEntry = ManagementGpbHelper.toCommandQueueEntry(queue, pc);
responseb.addEntry(qEntry);
}
completeOK(req, responseb.build(), SchemaRest.ListCommandQueueEntries.WRITE);
}
@Route(path = "/api/processors/:instance/:processor/cqueues/:cqueue/entries/:uuid", method = { "PATCH", "PUT", "POST" })
public void editQueueEntry(RestRequest req) throws HttpException {
Processor processor = verifyProcessor(req, req.getRouteParam("instance"), req.getRouteParam("processor"));
CommandQueueManager mgr = verifyCommandQueueManager(processor);
UUID entryId = UUID.fromString(req.getRouteParam("uuid"));
EditCommandQueueEntryRequest body = req.bodyAsMessage(SchemaRest.EditCommandQueueEntryRequest.MERGE).build();
String state = null;
if (body.hasState()) {
state = body.getState();
}
if (req.hasQueryParameter("state")) {
state = req.getQueryParameter("state");
}
if (state != null) {
// TODO queue manager currently iterates over all queues, which doesn't really match
// what we want. It would be better to assure only the queue from the URI is considered.
switch (state.toLowerCase()) {
case "released":
mgr.sendCommand(entryId, false);
break;
case "rejected":
String username = req.getUsername();
mgr.rejectCommand(entryId, username);
break;
default:
throw new BadRequestException("Unsupported state '" + state + "'");
}
}
completeOK(req);
}
private CommandQueueInfo toCommandQueueInfo(RestRequest req, CommandQueue queue, boolean detail) {
CommandQueueInfo.Builder b = CommandQueueInfo.newBuilder();
b.setInstance(queue.getChannel().getInstance());
b.setProcessorName(queue.getChannel().getName());
b.setName(queue.getName());
b.setState(queue.getState());
b.setNbSentCommands(queue.getNbSentCommands());
b.setNbRejectedCommands(queue.getNbRejectedCommands());
if (queue.getStateExpirationRemainingS() != -1) {
b.setStateExpirationTimeS(queue.getStateExpirationRemainingS());
}
if (detail) {
for (PreparedCommand pc : queue.getCommands()) {
CommandQueueEntry qEntry = ManagementGpbHelper.toCommandQueueEntry(queue, pc);
b.addEntry(qEntry);
}
}
if (!req.getOptions().contains(Option.NO_LINK)) {
b.setUrl(req.getApiURL() + "/processors/" + queue.getChannel().getInstance()
+ "/" + queue.getChannel().getName() + "/cqueues/" + queue.getName());
}
return b.build();
}
private CommandQueueManager verifyCommandQueueManager(Processor processor) throws BadRequestException {
ManagementService managementService = ManagementService.getInstance();
CommandQueueManager mgr = managementService.getCommandQueueManager(processor);
if (mgr == null) {
throw new BadRequestException("Commanding not enabled for processor '" + processor.getName() + "'");
}
return mgr;
}
private CommandQueue verifyCommandQueue(RestRequest req, CommandQueueManager mgr, String queueName) throws NotFoundException {
CommandQueue queue = mgr.getQueue(queueName);
if (queue == null) {
String processorName = mgr.getChannelName();
String instance = mgr.getInstance();
throw new NotFoundException(req, "No queue named '" + queueName + "' (processor: '" + instance + "/" + processorName + "')");
} else {
return queue;
}
}
}