/** * Copyright 2011 Intuit Inc. All Rights Reserved */ package com.intuit.tank.service.impl.v1.project; /* * #%L * Project 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.File; import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; 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 org.apache.commons.io.IOUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.intuit.tank.api.model.v1.project.ProjectContainer; import com.intuit.tank.api.model.v1.project.ProjectTO; import com.intuit.tank.api.service.v1.project.ProjectService; import com.intuit.tank.dao.BaseDao; import com.intuit.tank.dao.DataFileDao; import com.intuit.tank.dao.JobInstanceDao; import com.intuit.tank.dao.JobNotificationDao; import com.intuit.tank.dao.JobQueueDao; import com.intuit.tank.dao.JobRegionDao; import com.intuit.tank.dao.ProjectDao; import com.intuit.tank.dao.WorkloadDao; import com.intuit.tank.dao.util.ProjectDaoUtil; import com.intuit.tank.perfManager.workLoads.util.WorkloadScriptUtil; import com.intuit.tank.project.BaseEntity; import com.intuit.tank.project.DataFile; import com.intuit.tank.project.EntityVersion; import com.intuit.tank.project.JobConfiguration; import com.intuit.tank.project.JobInstance; import com.intuit.tank.project.JobQueue; import com.intuit.tank.project.JobRegion; import com.intuit.tank.project.Project; import com.intuit.tank.project.ProjectDTO; import com.intuit.tank.project.Workload; import com.intuit.tank.service.impl.v1.cloud.JobController; import com.intuit.tank.service.util.ResponseUtil; import com.intuit.tank.service.util.ServletInjector; import com.intuit.tank.vm.common.util.ReportUtil; /** * ProjectServiceV1 * * @author dangleton * */ @Path(ProjectService.SERVICE_RELATIVE_PATH) public class ProjectServiceV1 implements ProjectService { private static final Logger LOG = LogManager.getLogger(ProjectServiceV1.class); @Context private ServletContext servletContext; /** * @{inheritDoc */ @Override public String ping() { return "PONG " + getClass().getSimpleName(); } /** * @{inheritDoc */ @Override public Response deleteProject(int projectId) { return delete(projectId); } /** * @{inheritDoc */ @Override public Response deleteProjectPost(int projectId) { return delete(projectId); } /** * Check that project exists and delete it. * * @param projectId * @return Response suitable to pass to client */ private Response delete(int projectId) { ResponseBuilder responseBuilder = Response.noContent(); ProjectDao dao = new ProjectDao(); try { Project project = dao.findById(projectId); if (project == null) { LOG.warn("Proect with id " + projectId + "does not exist."); responseBuilder.status(Status.BAD_REQUEST); responseBuilder.entity("Project with id " + projectId + " does not exist."); } else { dao.delete(project); } } catch (RuntimeException e) { LOG.error("Error deleting project: " + e, e); responseBuilder.status(Status.INTERNAL_SERVER_ERROR); responseBuilder.entity("An error occurred while deleting the project."); } return responseBuilder.build(); } /** * @{inheritDoc */ @Override public StreamingOutput getTestScriptForJob(String jobId) { File f = ProjectDaoUtil.getScriptFile(jobId); if (!f.exists()) { if (NumberUtils.isNumber(jobId)) { JobInstance job = new JobInstanceDao().findById(Integer.parseInt(jobId)); if (job == null) { throw new RuntimeException("Cannot find Job with id of " + jobId); } ProjectDaoUtil.storeScriptFile(jobId, ProjectServiceUtil.getScriptString(job)); f = ProjectDaoUtil.getScriptFile(jobId); } else { throw new RuntimeException("Cannot create job script for non persisted jobs"); } } final File file = f; return new StreamingOutput() { public void write(OutputStream outputStream) { BufferedReader in = null; // Get the object of DataInputStream try { in = new BufferedReader(new FileReader(file)); IOUtils.copy(in, 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 StreamingOutput getTestScriptForProject(Integer projectId) { Project p = new ProjectDao().loadScripts(projectId); if (p == null) { throw new RuntimeException("Cannot find Project with id of " + projectId); } final String scriptString = WorkloadScriptUtil.getScriptForWorkload(p.getWorkloads().get(0), p.getWorkloads().get(0).getJobConfiguration()); return new StreamingOutput() { public void write(OutputStream outputStream) { // Get the object of DataInputStream try { IOUtils.write(scriptString, outputStream); } catch (IOException e) { LOG.error("Error streaming file: " + e.toString(), e); throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR); } finally { } } }; } /** * @{inheritDoc */ @Override public Response downloadTestScriptForJob(String jobId) { ResponseBuilder responseBuilder = Response.ok(); String filename = "job_" + jobId + "_H.xml"; responseBuilder.header("Content-Disposition", "attachment; filename=\"" + filename + "\""); responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); responseBuilder.type(MediaType.APPLICATION_OCTET_STREAM_TYPE).entity(getTestScriptForJob(jobId)); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response downloadTestScriptForProject(Integer projectId) { ResponseBuilder responseBuilder = Response.ok(); String filename = "project_" + projectId + "_H.xml"; responseBuilder.header("Content-Disposition", "attachment; filename=\"" + filename + "\""); responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl()); responseBuilder.type(MediaType.APPLICATION_OCTET_STREAM_TYPE).entity(getTestScriptForProject(projectId)); return responseBuilder.build(); } /** * @{inheritDoc */ @Override public Response getProjectNames() { ResponseBuilder responseBuilder = Response.ok(); List<Project> all = new ProjectDao().findAll(); List<ProjectTO> to = new ArrayList<ProjectTO>(); for (Project p : all) { to.add(ProjectServiceUtil.projectToTransferObject(p)); } ProjectContainer container = new ProjectContainer(to); responseBuilder.entity(container); return responseBuilder.build(); } @Override public Response runProject(Integer projectId) { ResponseBuilder responseBuilder = Response.ok(); ProjectDao projectDao = new ProjectDao(); Project project = projectDao.findById(projectId); if (project == null) { responseBuilder.status(Status.NOT_FOUND); responseBuilder.entity("Cannot find Project with id " + projectId); } else { JobInstance job = addJobToQueue(project); LOG.info("Job (" + job.getId() + ") requested with values: " + job); String jobId = Integer.toString(job.getId()); JobController controller = new ServletInjector<JobController>().getManagedBean(servletContext, JobController.class); controller.startJob(jobId); responseBuilder = Response.ok(); // add jobId to response responseBuilder.entity("Started job with id " + jobId); } return responseBuilder.build(); } public JobInstance addJobToQueue(Project p) { JobQueueDao jobQueueDao = new JobQueueDao(); // WorkloadDao wdao = new WorkloadDao(); DataFileDao dataFileDao = new DataFileDao(); JobNotificationDao jobNotificationDao = new JobNotificationDao(); JobRegionDao jobRegionDao = new JobRegionDao(); JobInstanceDao jobInstanceDao = new JobInstanceDao(); Workload workload = p.getWorkloads().get(0); JobConfiguration jc = workload.getJobConfiguration(); JobQueue queue = jobQueueDao.findOrCreateForProjectId(p.getId()); String name = p.getName() + "_" + workload.getJobConfiguration().getTotalVirtualUsers() + "_users_" + ReportUtil.getTimestamp(new Date()); JobInstance jobInstance = new JobInstance(workload, name); jobInstance.setScheduledTime(new Date()); jobInstance.setLocation(jc.getLocation()); jobInstance.setReportingMode(jc.getReportingMode()); jobInstance.getVariables().putAll(jc.getVariables()); // set version info if (jc.getDataFileIds() != null) { jobInstance.getDataFileVersions().addAll(getVersions(dataFileDao, jc.getDataFileIds(), DataFile.class)); } jobInstance.getNotificationVersions().addAll( getVersions(jobNotificationDao, workload.getJobConfiguration().getNotifications())); Set<JobRegion> jobRegions = JobRegionDao.cleanRegions(jc.getJobRegions()); jobInstance.setVariables(new HashMap<String, String>(workload.getJobConfiguration().getVariables())); jobInstance.setAllowOverride(workload.getJobConfiguration().isAllowOverride()); jobInstance.getJobRegionVersions().addAll(getVersions(jobRegionDao, jobRegions)); jobInstance = jobInstanceDao.saveOrUpdate(jobInstance); queue.addJob(jobInstance); jobQueueDao.saveOrUpdate(queue); storeScript(Integer.toString(jobInstance.getId()), workload, jobInstance); return jobInstance; } /** * @param dataFileDao2 * @param dataFileIds * @return */ @SuppressWarnings("rawtypes") private Set<EntityVersion> getVersions(BaseDao dao, Collection<Integer> dataFileIds, Class<? extends BaseEntity> entityClass) { HashSet<EntityVersion> result = new HashSet<EntityVersion>(); for (Integer id : dataFileIds) { int versionId = dao.getHeadRevisionNumber(id); result.add(new EntityVersion(id, versionId, entityClass)); } return result; } /** * @param dataFileDao2 * @param dataFileIds * @return */ @SuppressWarnings({ "rawtypes", "unchecked" }) private Set<EntityVersion> getVersions(BaseDao dao, Set<? extends BaseEntity> entities) { HashSet<Integer> ids = new HashSet<Integer>(); Class entityClass = null; for (BaseEntity entity : entities) { ids.add(entity.getId()); entityClass = entity.getClass(); } return getVersions(dao, ids, entityClass); } private void storeScript(String jobId, Workload workload, JobInstance job) { new WorkloadDao().loadScriptsForWorkload(workload); String scriptString = WorkloadScriptUtil.getScriptForWorkload(workload, job); ProjectDaoUtil.storeScriptFile(jobId, scriptString); } }