/** * Copyright 2011 Intuit Inc. All Rights Reserved */ package com.intuit.tank.service.impl.v1.script; /* * #%L * Script Rest Service * %% * Copyright (C) 2011 - 2015 Intuit Inc. * %% * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * #L% */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.StringReader; import java.net.URI; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.servlet.ServletContext; import javax.ws.rs.Path; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; 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 javax.ws.rs.core.StreamingOutput; import javax.ws.rs.core.UriInfo; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.intuit.tank.api.model.v1.script.ExternalScriptContainer; import com.intuit.tank.api.model.v1.script.ExternalScriptTO; import com.intuit.tank.api.model.v1.script.ScriptDescription; import com.intuit.tank.api.model.v1.script.ScriptDescriptionContainer; import com.intuit.tank.api.model.v1.script.ScriptFilterRequest; import com.intuit.tank.api.model.v1.script.ScriptStepContainer; import com.intuit.tank.api.model.v1.script.ScriptStepTO; import com.intuit.tank.api.model.v1.script.ScriptTO; import com.intuit.tank.api.model.v1.script.ScriptUploadRequest; import com.intuit.tank.api.script.util.ScriptServiceUtil; import com.intuit.tank.api.service.v1.script.ScriptService; import com.intuit.tank.dao.ExternalScriptDao; import com.intuit.tank.dao.FilterDao; import com.intuit.tank.dao.ScriptDao; import com.intuit.tank.dao.ScriptFilterDao; import com.intuit.tank.dao.ScriptFilterGroupDao; import com.intuit.tank.harness.data.HDWorkload; import com.intuit.tank.project.ExternalScript; import com.intuit.tank.project.Script; import com.intuit.tank.project.ScriptFilter; import com.intuit.tank.project.ScriptFilterGroup; import com.intuit.tank.project.ScriptStep; import com.intuit.tank.script.processor.ScriptProcessor; import com.intuit.tank.script.util.ScriptFilterUtil; import com.intuit.tank.service.util.ResponseUtil; import com.intuit.tank.service.util.ServletInjector; import com.intuit.tank.transform.scriptGenerator.ConverterUtil; import com.sun.jersey.multipart.FormDataBodyPart; import com.sun.jersey.multipart.FormDataMultiPart; /** * DataFileServiceV1 * * @author dangleton * */ /** * @author hsomani * */ @Path("/v1/script-service") public class ScriptServiceV1 implements ScriptService { private static final Logger LOG = LogManager.getLogger(ScriptServiceV1.class); @Context private ServletContext servletContext; @Context private UriInfo uriInfo; /** * @{inheritDoc */ @Override public String ping() { return "PONG " + getClass().getSimpleName(); } /** * @{inheritDoc */ @Override public Response updateTankScript(FormDataMultiPart formData) { ScriptTO scriptTo = null; InputStream is = null; Map<String, List<FormDataBodyPart>> fields = formData.getFields(); ScriptDao dao = new ScriptDao(); for (Entry<String, List<FormDataBodyPart>> entry : fields.entrySet()) { String formName = entry.getKey(); LOG.debug("Entry name: " + formName); for (FormDataBodyPart part : entry.getValue()) { MediaType mediaType = part.getMediaType(); LOG.debug("MediaType " + mediaType); if (MediaType.APPLICATION_OCTET_STREAM_TYPE.equals(mediaType)) { // get the file is = part.getValueAs(InputStream.class); } } } ResponseBuilder responseBuilder = null; if (is != null) { try { JAXBContext ctx = JAXBContext.newInstance(ScriptTO.class.getPackage().getName()); scriptTo = (ScriptTO) ctx.createUnmarshaller().unmarshal(is); Script script = ScriptServiceUtil.transferObjectToScript(scriptTo); if (script.getId() > 0) { Script existing = dao.findById(script.getId()); if (existing == null) { LOG.error("Error updating script: Script passed with unknown id."); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } if (!existing.getName().equals(script.getName())) { LOG.error("Error updating script: Cannot change the name of an existing Script."); throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } } script = dao.saveOrUpdate(script); responseBuilder = Response.ok(); responseBuilder.entity(Integer.toString(script.getId())); } catch (Exception e) { LOG.error("Error unmarshalling script: " + e.getMessage(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } finally { IOUtils.closeQuietly(is); } } return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response convertScript(FormDataMultiPart formData) { ScriptUploadRequest request = null; InputStream is = null; Map<String, List<FormDataBodyPart>> fields = formData.getFields(); ScriptDao dao = new ScriptDao(); for (Entry<String, List<FormDataBodyPart>> entry : fields.entrySet()) { String formName = entry.getKey(); LOG.debug("Entry name: " + formName); for (FormDataBodyPart part : entry.getValue()) { MediaType mediaType = part.getMediaType(); if (MediaType.APPLICATION_XML_TYPE.equals(mediaType) || MediaType.APPLICATION_JSON_TYPE.equals(mediaType)) { request = part.getEntityAs(ScriptUploadRequest.class); } else if (MediaType.TEXT_PLAIN_TYPE.equals(mediaType)) { String s = part.getEntityAs(String.class); if ("xmlString".equalsIgnoreCase(formName)) { try { JAXBContext ctx = JAXBContext.newInstance(ScriptUploadRequest.class.getPackage().getName()); request = (ScriptUploadRequest) ctx.createUnmarshaller().unmarshal( new StringReader(s)); } catch (JAXBException e) { throw new RuntimeException(e); } } } else if (MediaType.APPLICATION_OCTET_STREAM_TYPE.equals(mediaType)) { // get the file is = part.getValueAs(InputStream.class); } } } ResponseBuilder responseBuilder = null; if (request == null) { responseBuilder = Response.status(Status.BAD_REQUEST); responseBuilder.entity("Requests to store Scripts must include a ScriptUploadRequest."); } else { Script script = descriptorToScript(dao, request.getScript()); if (is != null) { try { ScriptProcessor scriptProcessor = new ServletInjector<ScriptProcessor>().getManagedBean( servletContext, ScriptProcessor.class); List<ScriptStep> scriptSteps = scriptProcessor.getScriptSteps(new BufferedReader( new InputStreamReader(is)), getFilters(request.getFilterIds())); scriptProcessor.setScriptSteps(script, scriptSteps); script = dao.saveOrUpdate(script); } finally { IOUtils.closeQuietly(is); } } try { URI location = uriInfo.getBaseUriBuilder().path(ScriptService.class) .path(ScriptService.class.getMethod("getScript", Integer.class)).build(script.getId()); responseBuilder = Response.created(location); } catch (Exception e) { LOG.error("Error building uri: " + e.getMessage(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } } return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response updateScript(Integer id, ScriptTO scriptTo) { Script s = ScriptServiceUtil.transferObjectToScript(scriptTo); ScriptDao dao = new ScriptDao(); Script storedScript = dao.findById(id); ResponseBuilder responseBuilder = null; if (storedScript != null) { try { s = dao.saveOrUpdate(s); URI location = uriInfo.getBaseUriBuilder().path(ScriptService.class) .path(ScriptService.class.getMethod("getScript", Integer.class)).build(s.getId()); responseBuilder = Response.created(location); } catch (Exception e) { LOG.error("Error building uri: " + e.getMessage(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } } else { responseBuilder = Response.status(Status.NOT_FOUND); } return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response deleteScript(Integer id) { return delete(id); } /** * Checks that the script with the given id exists. If it exists deletes the script and returns no content else * sends back a bad request status to the client. * * @param scriptId * scriptId is the id that will be used to delete the Script * @return Response with status BAD_REQUEST or noContent. */ private Response delete(int scriptId) { ResponseBuilder responseBuilder = Response.noContent(); ScriptDao dao = new ScriptDao(); try { Script script = dao.findById(scriptId); if (script == null) { LOG.warn("Script with id " + scriptId + " does not exist."); responseBuilder.status(Status.BAD_REQUEST); responseBuilder.entity("Script with id " + scriptId + "does not exist."); } else { dao.delete(script); } } catch (RuntimeException e) { LOG.error("Error deleting project : " + e, e); responseBuilder.status(Status.INTERNAL_SERVER_ERROR); responseBuilder.entity("An error occurred while deleting the Script"); } return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getScriptDescriptions() { ResponseBuilder responseBuilder = Response.ok(); ScriptDao dao = new ScriptDao(); List<Script> all = dao.findAll(); List<ScriptDescription> result = new ArrayList<ScriptDescription>(); for (Script s : all) { result.add(ScriptServiceUtil.scriptToScriptDescription(s)); } responseBuilder.entity(new ScriptDescriptionContainer(result)); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response newScript(ScriptTO scriptTo) { scriptTo.setCreated(null); scriptTo.setModified(null); scriptTo.setId(0); Script savedScript = new ScriptDao().saveOrUpdate(ScriptServiceUtil.transferObjectToScript(scriptTo)); ResponseBuilder responseBuilder = null; try { URI location = uriInfo.getBaseUriBuilder().path(ScriptService.class) .path(ScriptService.class.getMethod("getScript", Integer.class)).build(savedScript.getId()); responseBuilder = Response.created(location); } catch (Exception e) { LOG.error("Error building uri: " + e.getMessage(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getScript(Integer id) { ResponseBuilder responseBuilder = Response.ok(); ScriptDao dao = new ScriptDao(); Script script = dao.findById(id); if (script != null) { responseBuilder.entity(ScriptServiceUtil.scriptToTransferObject(script)); } else { responseBuilder = Response.noContent().status(Status.NOT_FOUND); } responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response downloadHarnessScript(Integer scriptId) { ResponseBuilder responseBuilder = Response.ok(); ScriptDao dao = new ScriptDao(); Script script = dao.findById(scriptId); if (script == null) { throw new RuntimeException("Cannot find Script with id of " + scriptId); } String filename = script.getName() + "_H.xml"; responseBuilder.header("Content-Disposition", "attachment; filename=\"" + filename + "\""); responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); responseBuilder.type(MediaType.APPLICATION_OCTET_STREAM_TYPE).entity(getTestScriptForScript(script)); return responseBuilder.build(); } /** * @{inheritDoc */ private StreamingOutput getTestScriptForScript(Script script) { HDWorkload hdWorkload = ConverterUtil.convertScriptToHdWorkload(script); final String scriptXML = ConverterUtil.getWorkloadXML(hdWorkload); return new StreamingOutput() { public void write(OutputStream outputStream) { BufferedReader in = null; try { IOUtils.write(scriptXML, outputStream); } catch (IOException e) { LOG.error("Error streaming file: " + e.toString(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } finally { IOUtils.closeQuietly(in); } } }; } /** * @{inheritDoc */ @Override public Response downloadScript(Integer id) { ResponseBuilder responseBuilder = Response.ok(); ScriptDao dao = new ScriptDao(); final Script script = dao.findById(id); if (script != null) { String filename = script.getName() + "_TS.xml"; responseBuilder.header("Content-Disposition", "attachment; filename=\"" + filename + "\""); responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); final ScriptTO scriptTO = ScriptServiceUtil.scriptToTransferObject(script); StreamingOutput so = new StreamingOutput() { public void write(OutputStream outputStream) { // Get the object of DataInputStream try { JAXBContext ctx = JAXBContext.newInstance(ScriptTO.class.getPackage().getName()); Marshaller marshaller = ctx.createMarshaller(); marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE); marshaller.marshal(scriptTO, outputStream); } catch (Exception e) { LOG.error("Error streaming file: " + e.toString(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } finally { } } }; responseBuilder.type(MediaType.APPLICATION_OCTET_STREAM_TYPE).entity(so); } else { responseBuilder = Response.noContent().status(Status.NOT_FOUND); } // add jobId to response return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getScriptSteps(Integer id, int start, int numSteps) { ResponseBuilder responseBuilder = Response.ok(); ScriptDao dao = new ScriptDao(); Script script = dao.findById(id); if (script != null) { int totalSize = script.getScriptSteps().size(); if (numSteps <= 0) { numSteps = totalSize; } if (start <= 0) { start = 0; } List<ScriptStepTO> stepSlice = new ArrayList<ScriptStepTO>(numSteps); for (int i = start; i < totalSize && i < start + numSteps; i++) { stepSlice.add(ScriptServiceUtil.scriptStepToTransferObject(script.getScriptSteps().get(i))); } ScriptStepContainer result = ScriptStepContainer.builder().withSteps(stepSlice) .withNumRemaining(totalSize - (start + stepSlice.size())).withNumRequsted(numSteps) .withNumReturned(stepSlice.size()).withStartIndex(start).build(); responseBuilder.entity(result); } else { responseBuilder.status(Status.NOT_FOUND); } responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getScriptDescription(Integer id) { ResponseBuilder responseBuilder = Response.ok(); ScriptDao dao = new ScriptDao(); Script script = dao.findById(id); if (script != null) { responseBuilder.entity(ScriptServiceUtil.scriptToScriptDescription(script)); } else { responseBuilder.status(Status.NOT_FOUND); } responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response scriptFilterRequest(ScriptFilterRequest filterRequest) { ResponseBuilder responseBuilder = null; ScriptDao dao = new ScriptDao(); try { Script script = dao.findById(filterRequest.getScriptId()); ScriptFilterUtil.applyFilters(filterRequest.getFilterIds(), script); dao.saveOrUpdate(script); URI location = uriInfo.getBaseUriBuilder().path(ScriptService.class) .path(ScriptService.class.getMethod("getScript", Integer.class)).build(script.getId()); responseBuilder = Response.created(location); } catch (Exception e) { LOG.error("Error Applying Filters: " + e.getMessage(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getExternalScript(Integer id) { ResponseBuilder responseBuilder = Response.ok(); ExternalScriptDao dao = new ExternalScriptDao(); ExternalScript script = dao.findById(id); if (script != null) { responseBuilder.entity(ScriptServiceUtil.externalScriptToTO(script)); } else { responseBuilder.status(Status.NOT_FOUND); } responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getExternalScripts() { ResponseBuilder responseBuilder = Response.ok(); ExternalScriptDao dao = new ExternalScriptDao(); List<ExternalScript> all = dao.findAll(); ExternalScriptContainer ret = new ExternalScriptContainer(); for (ExternalScript s : all) { ret.getScripts().add(ScriptServiceUtil.externalScriptToTO(s)); } responseBuilder.entity(ret); responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response saveOrUpdateExternalScript(ExternalScriptTO to) { ResponseBuilder responseBuilder = null; ExternalScriptDao dao = new ExternalScriptDao(); try { ExternalScript script = ScriptServiceUtil.TOToExternalScript(to); script = dao.saveOrUpdate(script); URI location = uriInfo.getBaseUriBuilder().path(ScriptService.class) .path(ScriptService.class.getMethod("getExternalScript", Integer.class)).build(script.getId()); responseBuilder = Response.created(location); } catch (Exception e) { LOG.error("Error Saving External Script: " + e.getMessage(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); return responseBuilder.build(); } private Script descriptorToScript(ScriptDao dao, ScriptDescription sd) { Script script; if (sd.getId() != null && sd.getId() != 0) { script = dao.findById(sd.getId()); script.setComments(sd.getComments()); script.setName(sd.getName()); script.setRuntime(sd.getRuntime()); script.setProductName(sd.getProductName()); script.setCreator(sd.getCreator()); } else { script = ScriptServiceUtil.scriptDescriptionToScript(sd); } return script; } private List<ScriptFilter> getFilters(List<Integer> filterIds) { List<ScriptFilter> filters = new ArrayList<ScriptFilter>(); for (Integer id : filterIds) { ScriptFilter filter = new FilterDao().findById(id); if (filter != null) { filters.add(filter); } } return filters; } /* * (non-Javadoc) * * @see com.intuit.tank.api.service.v1.script.ScriptService#deleteFilter(java.lang.Integer) */ @Override public Response deleteFilter(Integer id) { return deleteFilterHelper(id); } /** * Deletes script filter from the system. * * @param id * id is the id of the filter that is to be deleted * @return */ private Response deleteFilterHelper(Integer id) { ResponseBuilder responseBuilder = Response.noContent(); ScriptFilterGroupDao sfgd = new ScriptFilterGroupDao(); List<ScriptFilterGroup> scriptFilterGroupForFilter = sfgd.getScriptFilterGroupForFilter(id); for (Iterator<ScriptFilterGroup> iterator = scriptFilterGroupForFilter.iterator(); iterator.hasNext();) { ScriptFilterGroup scriptFilterGroup = iterator.next(); Set<ScriptFilter> filters = scriptFilterGroup.getFilters(); for (Iterator<ScriptFilter> iterator2 = filters.iterator(); iterator2.hasNext();) { ScriptFilter scriptFilter = iterator2.next(); if (scriptFilter.getId() == id) { iterator2.remove(); } } sfgd.saveOrUpdate(scriptFilterGroup); } ScriptFilterDao sfd = new ScriptFilterDao(); try { ScriptFilter scriptFilter = sfd.findById(id); if (scriptFilter == null) { LOG.warn("Script with id " + id + " does not exist."); responseBuilder.status(Status.BAD_REQUEST); responseBuilder.entity("Filter with id " + id + " does not exist."); } else { sfd.delete(scriptFilter); } } catch (RuntimeException e) { LOG.error("Error deleting script filter : " + e, e); responseBuilder.status(Status.INTERNAL_SERVER_ERROR); responseBuilder.entity("A server error occurred while deleting the filter."); } return responseBuilder.build(); } }