com.intuit.tank.service.impl.v1.automation.AutomationServiceV1.java Source code

Java tutorial

Introduction

Here is the source code for com.intuit.tank.service.impl.v1.automation.AutomationServiceV1.java

Source

/**
 * Copyright 2011 Intuit Inc. All Rights Reserved
 */
package com.intuit.tank.service.impl.v1.automation;

/*
 * #%L
 * Automation 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.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
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.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.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.intuit.tank.api.model.v1.automation.AutomationJobRegion;
import com.intuit.tank.api.model.v1.automation.AutomationRequest;
import com.intuit.tank.api.service.v1.automation.AutomationService;
import com.intuit.tank.dao.BaseDao;
import com.intuit.tank.dao.DataFileDao;
import com.intuit.tank.dao.FilterDao;
import com.intuit.tank.dao.FilterGroupDao;
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.ScriptDao;
import com.intuit.tank.dao.WorkloadDao;
import com.intuit.tank.dao.util.ProjectDaoUtil;
import com.intuit.tank.harness.StopBehavior;
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.JobDetailFormatter;
import com.intuit.tank.project.JobInstance;
import com.intuit.tank.project.JobQueue;
import com.intuit.tank.project.JobRegion;
import com.intuit.tank.project.JobValidator;
import com.intuit.tank.project.Project;
import com.intuit.tank.project.Script;
import com.intuit.tank.project.ScriptFilter;
import com.intuit.tank.project.ScriptFilterGroup;
import com.intuit.tank.project.ScriptGroup;
import com.intuit.tank.project.ScriptGroupStep;
import com.intuit.tank.project.ScriptStep;
import com.intuit.tank.project.TestPlan;
import com.intuit.tank.project.Workload;
import com.intuit.tank.script.processor.ScriptProcessor;
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.util.TestParamUtil;
import com.intuit.tank.util.TestParameterContainer;
import com.intuit.tank.vm.api.enumerated.ScriptDriver;
import com.intuit.tank.vm.api.enumerated.TerminationPolicy;
import com.intuit.tank.vm.common.TankConstants;
import com.intuit.tank.vm.common.util.ReportUtil;
import com.intuit.tank.vm.settings.ModificationType;
import com.intuit.tank.vm.settings.ModifiedEntityMessage;
import com.sun.jersey.multipart.FormDataBodyPart;
import com.sun.jersey.multipart.FormDataMultiPart;

/**
 * AutomationServiceV1
 * 
 * @author dangleton
 * 
 */
@Path("/v1/automation-service")
public class AutomationServiceV1 implements AutomationService {

    private static final Logger LOG = Logger.getLogger(AutomationServiceV1.class);

    @Context
    private ServletContext servletContext;

    /**
     * @{inheritDoc
     */
    @Override
    public String ping() {
        return "PONG " + getClass().getSimpleName();
    }

    /**
     * @{inheritDoc
     */
    @Override
    public Response runAutomationJob(FormDataMultiPart formData) {
        AutomationRequest request = null;
        InputStream is = null;
        Map<String, List<FormDataBodyPart>> fields = formData.getFields();
        for (Entry<String, List<FormDataBodyPart>> entry : fields.entrySet()) {
            String formName = entry.getKey();
            LOG.info("Entry name: " + formName);
            for (FormDataBodyPart part : entry.getValue()) {
                MediaType mediaType = part.getMediaType();
                System.out.println("MediaType " + mediaType);
                if (MediaType.APPLICATION_XML_TYPE.equals(mediaType)
                        || MediaType.APPLICATION_JSON_TYPE.equals(mediaType)) {
                    if ("automationRequest".equalsIgnoreCase(formName)) {
                        request = part.getEntityAs(AutomationRequest.class);
                    } else {
                        is = part.getValueAs(InputStream.class);
                    }
                } else if (MediaType.TEXT_PLAIN_TYPE.equals(mediaType)) {
                    String s = part.getEntityAs(String.class);
                    System.out.println("Plain Text Value: " + s);
                    if ("xmlString".equalsIgnoreCase(formName)) {
                        try {
                            JAXBContext ctx = JAXBContext
                                    .newInstance(AutomationRequest.class.getPackage().getName());
                            request = (AutomationRequest) 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 = Response.ok();
        if (request == null) {
            responseBuilder = Response.status(Status.BAD_REQUEST);
            responseBuilder.entity("Requests to run automation jobs must contain an AutomationRequest");
        } else {
            Script script = null;
            if (is != null) {
                try {
                    ScriptProcessor scriptProcessor = new ServletInjector<ScriptProcessor>()
                            .getManagedBean(servletContext, ScriptProcessor.class);
                    List<Integer> filterIds = getFilterList(request);
                    script = new Script();
                    script.setName(request.getScriptName());
                    scriptProcessor.setScript(script);
                    script.setProductName(request.getProductName());
                    script.setCreator(TankConstants.TANK_USER_SYSTEM);
                    List<ScriptStep> scriptSteps = scriptProcessor
                            .getScriptSteps(new BufferedReader(new InputStreamReader(is)), getFilters(filterIds));
                    List<ScriptStep> newSteps = new ArrayList<ScriptStep>();
                    for (ScriptStep step : scriptSteps) {
                        newSteps.add(step);
                    }
                    // script.setScriptSteps(newSteps);
                    //
                    // script.setScriptSteps(newSteps);
                    script = new ScriptDao().saveOrUpdate(script);
                    sendMsg(script, ModificationType.ADD);

                } catch (Exception e) {
                    LOG.error("Error starting script: " + e, e);
                    responseBuilder = Response.status(Status.INTERNAL_SERVER_ERROR);
                    responseBuilder.entity("An External Script failed with Exception: " + e.toString());
                } finally {
                    IOUtils.closeQuietly(is);
                }
            }
            // now send off to service
            Project p = getOrCreateProject(request);
            JobInstance job = addJobToQueue(p, request, script);
            LOG.info("Automation 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(jobId);
        }
        responseBuilder.cacheControl(ResponseUtil.getNoStoreCacheControl());
        return responseBuilder.build();

    }

    /**
     * @param request
     * @return
     */
    private synchronized Project getOrCreateProject(AutomationRequest request) {
        ProjectDao projectDao = new ProjectDao();
        ModificationType type = ModificationType.UPDATE;
        Project project = projectDao.findByName(request.getName());
        if (project == null) {
            Workload workload = new Workload();
            List<Workload> workloads = new ArrayList<Workload>();
            project = new Project();
            project.setName(request.getName());
            project.setProductName(request.getProductName());
            project.setCreator(TankConstants.TANK_USER_SYSTEM);
            workload.setName(request.getName());
            workloads.add(workload);
            workload.setParent(project);
            project.setWorkloads(workloads);
            project.setScriptDriver(ScriptDriver.Tank);
            project = projectDao.saveOrUpdateProject(project);
            type = ModificationType.ADD;
        }
        JobConfiguration jobConfiguration = project.getWorkloads().get(0).getJobConfiguration();
        // jobConfiguration.setRampTime(TimeUtil.parseTimeString(request.getRampTime()));
        jobConfiguration.setRampTimeExpression(request.getRampTime());
        jobConfiguration.setStopBehavior(request.getStopBehavior() != null ? request.getStopBehavior().name()
                : StopBehavior.END_OF_SCRIPT_GROUP.name());
        jobConfiguration.setSimulationTimeExpression(request.getSimulationTime());
        boolean hasSimTime = jobConfiguration.getSimulationTime() > 0
                || (StringUtils.isNotBlank(request.getSimulationTime())
                        && !"0".equals(request.getSimulationTime()));
        jobConfiguration.setTerminationPolicy(hasSimTime ? TerminationPolicy.time : TerminationPolicy.script);
        jobConfiguration.setUserIntervalIncrement(request.getUserIntervalIncrement());
        jobConfiguration.getJobRegions().clear();
        JobRegionDao jrd = new JobRegionDao();
        for (AutomationJobRegion r : request.getJobRegions()) {
            JobRegion jr = jrd.saveOrUpdate(new JobRegion(r.getRegion(), r.getUsers()));
            jobConfiguration.getJobRegions().add(jr);
        }

        Map<String, String> varMap = jobConfiguration.getVariables();
        varMap.putAll(request.getVariables());

        project = projectDao.saveOrUpdateProject(project);
        sendMsg(project, type);

        return project;
    }

    private void sendMsg(BaseEntity entity, ModificationType type) {
        MessageSender sender = new ServletInjector<MessageSender>().getManagedBean(servletContext,
                MessageSender.class);
        sender.sendEvent(new ModifiedEntityMessage(entity.getClass(), entity.getId(), type));
    }

    public JobInstance addJobToQueue(Project p, AutomationRequest request, Script script) {

        JobQueueDao jobQueueDao = new JobQueueDao();
        DataFileDao dataFileDao = new DataFileDao();
        JobNotificationDao jobNotificationDao = new JobNotificationDao();
        JobInstanceDao jobInstanceDao = new JobInstanceDao();

        Workload workload = p.getWorkloads().get(0);
        JobConfiguration jc = workload.getJobConfiguration();
        JobQueue queue = jobQueueDao.findOrCreateForProjectId(p.getId());
        String name = request.getScriptName() + "_" + workload.getJobConfiguration().getTotalVirtualUsers()
                + "_users_" + ReportUtil.getTimestamp(new Date());
        JobInstance jobInstance = new JobInstance(workload, name);
        jobInstance.setScheduledTime(new Date());
        jobInstance.setLocation(jc.getLocation());
        jobInstance.setLoggingProfile(jc.getLoggingProfile());
        jobInstance.setStopBehavior(jc.getStopBehavior());
        jobInstance.setReportingMode(jc.getReportingMode());
        jobInstance.getVariables().putAll(jc.getVariables());
        // set version info
        if (request.getDataFileIds() != null && !request.getDataFileIds().isEmpty()) {
            jobInstance.getDataFileVersions()
                    .addAll(getVersions(dataFileDao, request.getDataFileIds(), DataFile.class));
        } else {
            jobInstance.getDataFileVersions().addAll(
                    getVersions(dataFileDao, workload.getJobConfiguration().getDataFileIds(), DataFile.class));
        }
        jobInstance.getNotificationVersions()
                .addAll(getVersions(jobNotificationDao, workload.getJobConfiguration().getNotifications()));
        JobValidator validator = new JobValidator(workload.getTestPlans(), jobInstance.getVariables(), false);
        long maxDuration = 0;
        for (TestPlan plan : workload.getTestPlans()) {
            maxDuration = Math.max(validator.getDurationMs(plan.getName()), maxDuration);
        }
        TestParameterContainer times = TestParamUtil.evaluateTestTimes(maxDuration, jc.getRampTimeExpression(),
                jc.getSimulationTimeExpression());
        jobInstance.setExecutionTime(maxDuration);
        jobInstance.setRampTime(times.getRampTime());
        jobInstance.setSimulationTime(times.getSimulationTime());
        int totalVirtualUsers = 0;
        for (JobRegion region : jc.getJobRegions()) {
            totalVirtualUsers += TestParamUtil.evaluateExpression(region.getUsers(), maxDuration,
                    times.getSimulationTime(), times.getRampTime());
            jobInstance.getJobRegionVersions().add(new EntityVersion(region.getId(), 0, JobRegion.class));
        }
        jobInstance.setTotalVirtualUsers(totalVirtualUsers);
        queue.addJob(jobInstance);
        if (script != null) {
            workload.getTestPlans().clear();
            TestPlan plan = TestPlan.builder().name("default test plan").usersPercentage(100).build();
            workload.addTestPlan(plan);
            ScriptGroup scriptGroup = new ScriptGroup();
            scriptGroup.setName("Script Group 1");
            scriptGroup.setLoop(1);
            ScriptGroupStep step = new ScriptGroupStep();
            step.setLoop(1);
            step.setScript(script);
            scriptGroup.addScriptGroupStep(step);
            plan.addScriptGroup(scriptGroup);
        }
        workload = new WorkloadDao().saveOrUpdate(workload);
        String jobDetails = JobDetailFormatter.createJobDetails(
                new JobValidator(workload.getTestPlans(), jobInstance.getVariables(), false), workload,
                jobInstance);
        jobInstance.setJobDetails(jobDetails);
        jobInstance = jobInstanceDao.saveOrUpdate(jobInstance);
        jobQueueDao.saveOrUpdate(queue);

        storeScript(Integer.toString(jobInstance.getId()), workload, jobInstance);
        return jobInstance;
    }

    /**
     * @param dao
     * @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 dao
     * @param entities
     * @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);
    }

    /**
     * @param request
     * @return
     */
    private List<Integer> getFilterList(AutomationRequest request) {
        Set<Integer> ret = new HashSet<Integer>();
        ret.addAll(request.getFilterIds());
        FilterGroupDao dao = new FilterGroupDao();
        for (Integer id : request.getFilterGroupIds()) {
            ScriptFilterGroup group = dao.findById(id);
            if (group != null) {
                for (ScriptFilter filter : group.getFilters()) {
                    ret.add(filter.getId());
                }
            }
        }
        return new ArrayList<Integer>(ret);
    }

    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;
    }

}