/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of the License * at: * * http://opensource.org/licenses/ecl2.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * */ package org.opencastproject.execute.impl.endpoint; import org.opencastproject.execute.api.ExecuteException; import org.opencastproject.execute.api.ExecuteService; import org.opencastproject.job.api.JaxbJob; import org.opencastproject.job.api.Job; import org.opencastproject.job.api.JobProducer; import org.opencastproject.mediapackage.MediaPackage; import org.opencastproject.mediapackage.MediaPackageElement; import org.opencastproject.mediapackage.MediaPackageElementParser; import org.opencastproject.mediapackage.MediaPackageException; import org.opencastproject.mediapackage.MediaPackageParser; import org.opencastproject.rest.AbstractJobProducerEndpoint; import org.opencastproject.serviceregistry.api.ServiceRegistry; import org.opencastproject.util.doc.rest.RestParameter; import org.opencastproject.util.doc.rest.RestQuery; import org.opencastproject.util.doc.rest.RestResponse; import org.opencastproject.util.doc.rest.RestService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.FormParam; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; /** * The REST endpoint for {@link ExecuteService}s */ @Path("/") // Endpoint to the execute service, that runs CLI commands using MediaPackageElement's as parameters @RestService(name = "execute", title = "Execute Service", notes = {"" }, abstractText = "Runs CLI commands with MediaPackageElement's as parameters") public class ExecuteRestEndpoint extends AbstractJobProducerEndpoint { /** The logging facility */ private static final Logger logger = LoggerFactory.getLogger(ExecuteRestEndpoint.class); /** The text analyzer */ protected ExecuteService service; @POST @Produces(MediaType.TEXT_XML) @Path(ExecuteService.ENDPOINT_NAME) @RestQuery(name = "name", description = "Executes the given command", restParameters = { @RestParameter(description = "The command to execute", isRequired = true, name = ExecuteService.EXEC_FORM_PARAM, type = RestParameter.Type.STRING), @RestParameter(description = "The mediapackage to apply the command to. Either this or " + ExecuteService.INPUT_ELEM_FORM_PARAM + " are required", isRequired = false, name = ExecuteService.INPUT_MP_FORM_PARAM, type = RestParameter.Type.TEXT), @RestParameter(description = "The arguments to the command", isRequired = true, name = ExecuteService.PARAMS_FORM_PARAM, type = RestParameter.Type.STRING), @RestParameter(description = "The estimated load placed on the system by this command", isRequired = false, name = ExecuteService.LOAD_FORM_PARAM, type = RestParameter.Type.FLOAT), @RestParameter(description = "The mediapackage element to apply the command to. Either this or " + ExecuteService.INPUT_MP_FORM_PARAM + " are required", isRequired = false, name = ExecuteService.INPUT_ELEM_FORM_PARAM, type = RestParameter.Type.TEXT), @RestParameter(description = "The mediapackage element produced by the command", isRequired = false, name = ExecuteService.OUTPUT_NAME_FORM_PARAMETER, type = RestParameter.Type.STRING), @RestParameter(description = "The type of the returned element", isRequired = false, name = ExecuteService.TYPE_FORM_PARAMETER, type = RestParameter.Type.STRING) }, reponses = { @RestResponse(description = "XML-encoded Job is returned.", responseCode = HttpServletResponse.SC_NO_CONTENT), @RestResponse(description = "Service unavailabe or not currently present", responseCode = HttpServletResponse.SC_SERVICE_UNAVAILABLE), @RestResponse(description = "Incorrect parameters", responseCode = HttpServletResponse.SC_BAD_REQUEST), @RestResponse(description = "Problem executing the command or serializing the arguments/results", responseCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR) }, returnDescription = "") public Response execute(@FormParam(ExecuteService.EXEC_FORM_PARAM) String exec, @FormParam(ExecuteService.PARAMS_FORM_PARAM) String params, @FormParam(ExecuteService.LOAD_FORM_PARAM) Float loadParam, @FormParam(ExecuteService.INPUT_ELEM_FORM_PARAM) String inputElementStr, @FormParam(ExecuteService.INPUT_MP_FORM_PARAM) String inputMpStr, @FormParam(ExecuteService.OUTPUT_NAME_FORM_PARAMETER) String outputFileName, @FormParam(ExecuteService.TYPE_FORM_PARAMETER) String elementTypeStr) { checkNotNull(service); try { MediaPackageElement.Type expectedType = null; if (elementTypeStr != null) { for (MediaPackageElement.Type candidateType : MediaPackageElement.Type.values()) if (candidateType.toString().equalsIgnoreCase(elementTypeStr)) { expectedType = candidateType; break; } if (expectedType == null) { logger.error("Wrong element type specified: {}.", elementTypeStr); return Response.status(Response.Status.BAD_REQUEST).build(); } } float load = 1.0f; if (loadParam != null) { load = loadParam; } Job retJob = null; if ((inputElementStr != null) && (inputMpStr != null)) { logger.error("Only one input MediaPackage OR input MediaPackageElement can be set at the same time"); return Response.status(Response.Status.BAD_REQUEST).build(); } else if ((inputElementStr != null) && (inputMpStr == null)) { MediaPackageElement inputElement = MediaPackageElementParser.getFromXml(inputElementStr); retJob = service.execute(exec, params, inputElement, outputFileName, expectedType, load); } else if ((inputElementStr == null) && (inputMpStr != null)) { MediaPackage inputMp = MediaPackageParser.getFromXml(inputMpStr); retJob = service.execute(exec, params, inputMp, outputFileName, expectedType, load); } else { logger.error("Not input MediaPackage OR not input MediaPackageElement"); return Response.status(Response.Status.BAD_REQUEST).build(); } return Response.ok(new JaxbJob(retJob)).build(); } catch (IllegalArgumentException e) { logger.error("The expected element type is required if an output filename is specified"); return Response.status(Response.Status.BAD_REQUEST).build(); } catch (MediaPackageException e) { logger.error("Received excepcion: {}", e.getMessage()); return Response.serverError().build(); } catch (ExecuteException e) { logger.error("Received error from the execute service: {}", e.getMessage()); return Response.serverError().build(); } } /** * Sets the service * * @param service */ public void setExecuteService(ExecuteService service) { this.service = service; } /** * {@inheritDoc} * * @see org.opencastproject.rest.AbstractJobProducerEndpoint#getService() */ @Override public JobProducer getService() { if (service instanceof JobProducer) return (JobProducer) service; else return null; } /** * Checks if the service or services are available, if not it handles it by returning a 503 with a message * * @param services * an array of services to check */ protected void checkNotNull(Object... services) { if (services != null) { for (Object object : services) { if (object == null) { throw new javax.ws.rs.WebApplicationException(javax.ws.rs.core.Response.Status.SERVICE_UNAVAILABLE); } } } } /* (non-Javadoc) * @see org.opencastproject.rest.AbstractJobProducerEndpoint#getServiceRegistry() */ public ServiceRegistry getServiceRegistry() { // FIXME: Why is this in the abstract ancestor? return null; } }