/**
* Copyright 2011 Intuit Inc. All Rights Reserved
*/
package com.intuit.tank.notification;
/*
* #%L
* JSF Support Beans
* %%
* 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 static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_DATA_FILES_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_DURATION_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_END_TIME_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_EVENT_NAME_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_EVENT_TIME_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_JOB_ID_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_JOB_NAME_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_LOAD_START_TIME_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_LOCATION_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_NUM_USERS_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_PREDICTED_END_TIME_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_PROJECT_ID_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_PROJECT_NAME_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_RAMP_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_SCRIPT_INFO_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_START_TIME_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_STEADY_STATE_END_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_STEADY_STATE_START_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_SUMMARY_DATA_URL_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_TERMINATION_POLICY_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_TIMING_DATA_URL_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_VALIDATION_FAILURES_KEY;
import static com.intuit.tank.vm.common.TankConstants.NOTIFICATIONS_EVENT_VARIABLES_KEY;
import java.text.NumberFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import com.intuit.tank.api.cloud.VMTracker;
import com.intuit.tank.api.model.v1.cloud.CloudVmStatus;
import com.intuit.tank.api.model.v1.cloud.CloudVmStatusContainer;
import com.intuit.tank.api.model.v1.cloud.ValidationStatus;
import com.intuit.tank.api.service.v1.report.ReportService;
import com.intuit.tank.dao.DataFileDao;
import com.intuit.tank.dao.JobInstanceDao;
import com.intuit.tank.dao.WorkloadDao;
import com.intuit.tank.harness.StopBehavior;
import com.intuit.tank.logging.LoggingProfile;
import com.intuit.tank.project.DataFile;
import com.intuit.tank.project.EntityVersion;
import com.intuit.tank.project.JobInstance;
import com.intuit.tank.project.Project;
import com.intuit.tank.project.Script;
import com.intuit.tank.project.ScriptGroup;
import com.intuit.tank.project.ScriptGroupStep;
import com.intuit.tank.project.TestPlan;
import com.intuit.tank.project.Workload;
import com.intuit.tank.vm.common.TankConstants;
import com.intuit.tank.vm.event.JobEvent;
import com.intuit.tank.vm.event.NotificationContext;
import com.intuit.tank.vm.settings.TankConfig;
import com.intuit.tank.vm.settings.TimeUtil;
/**
* NotificationContextBuilder
*
* @author dangleton
*
*/
public class NotificationContextBuilder {
/**
*
*/
private static final String N_A = "N/A";
private NotificationContext context = new NotificationContext();
TankConfig config = new TankConfig();
private JobInstance jobInstance;
private VMTracker vmTracker;
public NotificationContextBuilder(JobEvent e, VMTracker tracker) {
// build context
this.vmTracker = tracker;
JobInstance jobInstance = new JobInstanceDao().findById(Integer.parseInt(e.getJobId()));
Workload workload = new WorkloadDao().findById(jobInstance.getWorkloadId());
CloudVmStatusContainer container = vmTracker.getVmStatusForJob(e.getJobId());
this.jobInstance = jobInstance;
addJobInfo(jobInstance);
addTrackerInfo(container);
addProjectInfo(workload);
addJobEventInfo(e);
addCalculatedTimes(container);
}
public NotificationContextBuilder(JobEvent event, Workload workload, JobInstance jobInstance,
CloudVmStatusContainer container) {
this.jobInstance = jobInstance;
addJobInfo(jobInstance);
addTrackerInfo(container);
addProjectInfo(workload);
addJobEventInfo(event);
addCalculatedTimes(container);
}
public NotificationContext getContext() {
return context;
}
/**
* @param jobId
*/
private void addProjectInfo(Workload workload) {
if (workload != null) {
Project project = workload.getProject();
context.addContextEntry(NOTIFICATIONS_EVENT_PROJECT_NAME_KEY, cleanString(project.getName()))
.addContextEntry(NOTIFICATIONS_EVENT_PROJECT_ID_KEY, Integer.toString(project.getId()));
} else {
context.addContextEntry(NOTIFICATIONS_EVENT_PROJECT_NAME_KEY, N_A)
.addContextEntry(NOTIFICATIONS_EVENT_PROJECT_ID_KEY, N_A);
}
addScriptInfo(workload);
}
/**
* @param jobId
*/
private void addTrackerInfo(CloudVmStatusContainer container) {
ValidationStatus failures = new ValidationStatus();
String actualDuration = N_A;
Date startTime = container != null && container.getStartTime() != null ? container.getStartTime() : new Date();
Date endTime = container != null && container.getEndTime() != null ? container.getEndTime() : null;
if (container != null) {
if (endTime != null && startTime != null) {
actualDuration = TimeUtil.toTimeString(endTime.getTime() - startTime.getTime());
}
for (CloudVmStatus status : container.getStatuses()) {
failures.addFailures(status.getValidationFailures());
}
}
context.addContextEntry(NOTIFICATIONS_EVENT_START_TIME_KEY, cleanDate(startTime))
.addContextEntry(NOTIFICATIONS_EVENT_END_TIME_KEY, cleanDate(endTime));
context.addContextEntry(TankConstants.NOTIFICATIONS_EVENT_ACTUAL_DURTION, actualDuration);
context.addContextEntry(NOTIFICATIONS_EVENT_VALIDATION_FAILURES_KEY, formatInt(failures.getTotal()));
}
private void addJobEventInfo(JobEvent e) {
context.getContext().putAll(e.getExtraContext());
context.addContextEntry(NOTIFICATIONS_EVENT_EVENT_NAME_KEY, e.getEvent().getDisplay());
context.addContextEntry(NOTIFICATIONS_EVENT_EVENT_TIME_KEY, cleanDate(new Date()));
context.addContextEntry(TankConstants.NOTIFICATIONS_EVENT_BASE_URL_KEY, config.getControllerBase());
}
/**
* @param jobInstance
*/
private void addJobInfo(JobInstance jobInstance) {
context.addContextEntry(NOTIFICATIONS_EVENT_JOB_NAME_KEY, cleanString(jobInstance.getName()));
context.addContextEntry(NOTIFICATIONS_EVENT_JOB_ID_KEY, Integer.toString(jobInstance.getId()));
context.addContextEntry(NOTIFICATIONS_EVENT_RAMP_KEY, TimeUtil.toTimeString(jobInstance.getRampTime()));
context.addContextEntry(NOTIFICATIONS_EVENT_NUM_USERS_KEY, formatInt(jobInstance.getTotalVirtualUsers()));
context.addContextEntry(NOTIFICATIONS_EVENT_TERMINATION_POLICY_KEY, jobInstance.getTerminationPolicy()
.getDisplay());
context.addContextEntry(NOTIFICATIONS_EVENT_VARIABLES_KEY, cleanString(mapToString(jobInstance.getVariables())));
context.addContextEntry(NOTIFICATIONS_EVENT_LOCATION_KEY, cleanString(jobInstance.getLocation()));
context.addContextEntry(TankConstants.NOTIFICATIONS_EVENT_LOGGING_PROFILE_KEY,
LoggingProfile.fromString(jobInstance.getLoggingProfile()).getDisplayName());
context.addContextEntry(TankConstants.NOTIFICATIONS_EVENT_STOP_BEHAVIOR_KEY,
StopBehavior.fromString(jobInstance.getStopBehavior()).getDisplay());
context.addContextEntry(NOTIFICATIONS_EVENT_DURATION_KEY,
TimeUtil.toTimeString(jobInstance.getSimulationTime()));
String dataFiles = getDataFileString(jobInstance);
context.addContextEntry(NOTIFICATIONS_EVENT_DATA_FILES_KEY, cleanString(dataFiles));
String jobId = Integer.toString(jobInstance.getId());
context.addContextEntry(NOTIFICATIONS_EVENT_TIMING_DATA_URL_KEY, getTimingDataUrl(jobId));
context.addContextEntry(NOTIFICATIONS_EVENT_SUMMARY_DATA_URL_KEY, getTimingSummaryUrl(jobId));
context.addContextEntry(NOTIFICATIONS_EVENT_LOAD_START_TIME_KEY, cleanDate(jobInstance.getStartTime()));
}
private String cleanString(String s) {
return StringUtils.isBlank(s) ? NotificationContextBuilder.N_A : s;
}
private String cleanDate(Date d) {
return d == null ? NotificationContextBuilder.N_A : DateFormatUtils.format(d, TankConstants.DATE_FORMAT_WITH_TIMEZONE);
}
private String formatInt(int i) {
return NumberFormat.getIntegerInstance().format(i);
}
private String getDataFileString(JobInstance jobInstance) {
DataFileDao dataFileDao = new DataFileDao();
StringBuilder dataFiles = new StringBuilder();
for (EntityVersion entity : jobInstance.getDataFileVersions()) {
if (dataFiles.length() != 0) {
dataFiles.append(", ");
}
DataFile df = dataFileDao.findById(entity.getObjectId());
if (df != null) {
dataFiles.append(df.getPath());
}
}
return dataFiles.toString();
}
private void addCalculatedTimes(CloudVmStatusContainer container) {
long duration = jobInstance.getSimulationTime();
long ramp = jobInstance.getRampTime();
Date startTime = container != null && container.getStartTime() != null ? container.getStartTime() : new Date();
Date loadStartTime = jobInstance.getStartTime();
Date calcTime = loadStartTime != null ? loadStartTime : startTime;
Date predictedEndTimeDate = new Date(calcTime.getTime() + duration + ramp);
Date steadyStateStartDate = new Date(calcTime.getTime() + ramp);
Date steadyStateEndDate = new Date(calcTime.getTime() + duration);
context.addContextEntry(NOTIFICATIONS_EVENT_PREDICTED_END_TIME_KEY, cleanDate(predictedEndTimeDate))
.addContextEntry(NOTIFICATIONS_EVENT_STEADY_STATE_START_KEY, cleanDate(steadyStateStartDate))
.addContextEntry(NOTIFICATIONS_EVENT_STEADY_STATE_END_KEY, cleanDate(steadyStateEndDate));
}
private String mapToString(Map<String, String> map) {
StringBuilder ret = new StringBuilder();
if (!map.isEmpty()) {
ret.append("[");
for (Entry<String, String> entry : map.entrySet()) {
if (ret.length() != 1) {
ret.append(", ");
}
ret.append(entry.getKey()).append(" = ").append(entry.getValue());
}
ret.append("]");
}
return ret.toString();
}
private void addScriptInfo(Workload workload) {
StringBuilder ret = new StringBuilder();
if (workload != null) {
List<TestPlan> testPlans = workload.getTestPlans();
for (TestPlan plan : testPlans) {
ret.append("Test Plan: ").append(plan.getName());
ret.append("<br/>\n");
for (ScriptGroup group : plan.getScriptGroups()) {
ret.append(" ");
ret.append("Group: " + group.getName());
if (group.getLoop() > 1) {
ret.append(" (Loops: " + group.getLoop() + ")");
}
ret.append("<br/>\n");
for (ScriptGroupStep groupStep : group.getScriptGroupSteps()) {
Script script = groupStep.getScript();
ret.append(" ");
ret.append(" ");
ret.append("Script: " + script.getName());
if (groupStep.getLoop() > 1) {
ret.append(" (Loops: " + groupStep.getLoop() + ")");
}
ret.append("<br/>\n");
}
}
}
}
context = context.addContextEntry(NOTIFICATIONS_EVENT_SCRIPT_INFO_KEY, ret.toString());
}
private String getTimingDataUrl(String jobId) {
StringBuilder ret = new StringBuilder();
ret.append(config.getControllerBase());
ret.append(TankConstants.REST_SERVICE_CONTEXT + ReportService.SERVICE_RELATIVE_PATH
+ ReportService.METHOD_TIMING_CSV);
ret.append("/");
ret.append(jobId);
return ret.toString();
}
private String getTimingSummaryUrl(String jobId) {
StringBuilder ret = new StringBuilder();
ret.append(config.getControllerBase());
ret.append(TankConstants.REST_SERVICE_CONTEXT + ReportService.SERVICE_RELATIVE_PATH
+ ReportService.METHOD_TIMING_SUMMARY_HTML);
ret.append("/");
ret.append(jobId);
return ret.toString();
}
}